[
  {
    "path": ".gitignore",
    "content": "syntax:glob\nbuild\n*.pem\n.DS_Store\ntarget\nIcon?\nehthumbs.db\nThumbs.db\n*.crx\n*.zip\npkg\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2010, David Heaton\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n \n     * Neither the name of bit155 nor the names of its contributors\n       may be used to endorse or promote products derived from this software\n       without specific prior written permission.\n \nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "README.md",
    "content": "Scraper\n=======\n\nA Google Chrome extension for getting data out of web pages and into spreadsheets.\n\nUsage\n-----\n\nHighlight a part of the page that is similar to what you want to scrape. Right-click and select the \"Scrape selected...\" item. The scraper window will appear, showing you the initial results. You can export the table to by pressing the \"Export to Google Docs...\" button or use the left-hand pane to further refine or customize your scraping.\n\nThe \"Selector\" section lets you change which page elements are scraped. You can specify the query as either a [jQuery selector](http://api.jquery.com/category/selectors/), or in [XPath](http://www.w3schools.com/XPath/xpath_intro.asp).\n\nYou may also customize the columns of the table in the \"Columns\" section. These must be specified in XPath. You can specify names for columns if you would like.\n\nSelecting the \"Exclude empty results\" filter will prevent any matches that contain no column values from appearing in the table.\n\nAfter making any customizations, you must press the \"Scrape\" button to update the table of results.\n\nDownload\n--------\n\nDownload the extension from [http://chrome.google.com/extensions/detail/mbigbapnjcgaffohmbkdlecaccepngjd](http://chrome.google.com/extensions/detail/mbigbapnjcgaffohmbkdlecaccepngjd).\n\nGet the sources from [https://github.com/mnmldave/scraper](https://github.com/mnmldave/scraper).\n\nBuilding\n--------\n\nYou don't need to 'build' this extension per se. To test it out, you first \nneed to navigate to `chrome://extensions` from Google Chrome then expand \"Developer Mode\". Click the \"Load unpacked extension...\" button and point it to the `src` directory.\n\nLearn more about plugin development from the [Google Chrome Extensions](http://code.google.com/chrome/extensions/index.html \"Google Chrome Extensions - Google Code\") page.\n\nA `Rakefile` is included for compiling the Google Chrome extension into a\nzip file. It also does javascript and css minification.\n\nLicense\n-------\n\nScraper is open-sourced under a BSD license which you can find in `LICENSE.txt`.\n\nCredits\n-------\n\nMany of the icons used in this extension are from the generous [Yusuke Kamiyamane](http://p.yusukekamiyamane.com/).\n\n\n-----------------------------------------------------------------------------\nCopyright (c) 2010 David Heaton (dave@bit155.com)"
  },
  {
    "path": "Rakefile",
    "content": "# Copyright (c) 2010, David Heaton\n# All rights reserved.\n# \n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n# \n#     * Redistributions of source code must retain the above copyright notice,\n#       this list of conditions and the following disclaimer.\n#  \n#     * Redistributions in binary form must reproduce the above copyright\n#       notice, this list of conditions and the following disclaimer in the\n#       documentation and/or other materials provided with the distribution.\n#  \n#     * Neither the name of bit155 nor the names of its contributors\n#       may be used to endorse or promote products derived from this software\n#       without specific prior written permission.\n#  \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nrequire 'json'\nrequire 'yui/compressor'\nrequire 'closure-compiler'\n\ntask :default => [:rebuild, :repackage]\n\n# Metadata\n# --------------------------------------------------------------------------\n\nmanifest = open(File.join('src', 'manifest.json')) do |file|\n  JSON.load(file)\nend\n\nname = manifest['name']\nversion = manifest['version']\n\n\n# Building\n# --------------------------------------------------------------------------\n\nbuild_dir = 'build'\n\ndesc 'Rebuilds the extension'\ntask :rebuild => [:clobber_build, :build]\n\ndesc 'Removes build artifacts'\ntask :clobber_build do\n  rmtree build_dir rescue nil\nend\n\ndesc 'Builds the extension'\nfile build_dir do\n  source_files = Dir.glob(File.join('src', '**'))\n  mkdir_p build_dir rescue nil\n  cp_r source_files, build_dir\n  \n  # compress css\n  css_compressor = YUI::CssCompressor.new\n  Dir.glob(File.join(build_dir, '**', '*.css')) do |path|\n    puts 'Compressing: ' + path\n    css = File.open(path, 'r') { |file| css_compressor.compress(file) }\n    File.open(path, 'w') { |file| file.write(css) }\n  end\n  \n  # compress javascript\n  compiler = Closure::Compiler.new\n  Dir.glob(File.join(build_dir, '**', '*.js')) do |path|\n    puts 'Compiling: ' + path\n    begin\n      js = compiler.compile(File.read(path))\n      File.open(path, 'w') { |file| file.write(js) }\n    rescue\n      print 'Failed: ', $!, \"\\n\"\n    end\n  end\nend\n\n# Packaging\n# --------------------------------------------------------------------------\n\npackage_name = \"#{name}-#{version}\"\npackage_dir = 'pkg'\npackage_dir_path = File.join(package_dir, package_name)\nzip_file = \"#{package_name}.zip\"\n\n# most of this packaging stuff right from rake/packagetask\ndesc 'Packages the extension'\ntask :package => [\"#{package_dir}/#{zip_file}\"]\nfile \"#{package_dir}/#{zip_file}\" => package_dir_path do\n  chdir(package_dir) do\n    sh %{zip -r #{zip_file} #{package_name}}\n  end\nend\n\ndirectory package_dir\n\nfile package_dir_path => [package_dir, build_dir] do\n  chdir(build_dir) do\n    Dir.glob('**/*').each do |fn|\n      f = File.join(File.dirname(__FILE__), package_dir_path, fn)\n      fdir = File.dirname(f)\n      mkdir_p(fdir) if !File.exist?(fdir)\n      if File.directory?(fn)\n        mkdir_p(f)\n      else\n        rm_f f\n        safe_ln(fn, f)\n      end\n    end\n  end\nend\n\ndesc 'Removes the package artifacts'\ntask :clobber_package do\n  rmtree package_dir rescue nil\nend\n\ndesc 'Repackages the extension'\ntask :repackage => [:clobber_package, :package]\n\ndesc 'Removes all rake artifacts'\ntask :clobber => [:clobber_package, :clobber_build]\n"
  },
  {
    "path": "src/background.html",
    "content": "<!DOCTYPE html>\n\n<!-- \nCopyright (c) 2010, David Heaton\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n \n     * Neither the name of bit155 nor the names of its contributors\n       may be used to endorse or promote products derived from this software\n       without specific prior written permission.\n \nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \n-->\n\n<html>\n<head>\n  <script type=\"text/javascript\" src=\"chrome_ex_oauthsimple.js\"></script>\n  <script type=\"text/javascript\" src=\"chrome_ex_oauth.js\"></script>\n  <script type=\"text/javascript\" src=\"lib/jquery-ui-1.8.6/js/jquery-1.4.2.js\"></script>\n  <script type=\"text/javascript\" src=\"js/shared.js\"></script>\n  <script type=\"text/javascript\" src=\"js/bit155/attr.js\"></script>\n  <script type=\"text/javascript\" src=\"js/bit155/scraper.js\"></script>\n  <script type=\"text/javascript\" src=\"js/background.js\"></script>\n</head>\n<body>\n</body>\n</html>"
  },
  {
    "path": "src/chrome_ex_oauth.html",
    "content": "<!DOCTYPE html>\n<!--\n * Copyright (c) 2009 The Chromium Authors. All rights reserved.  Use of this\n * source code is governed by a BSD-style license that can be found in the\n * LICENSE file.\n-->\n<html>\n  <head>\n    <title>OAuth Redirect Page</title>\n    <style type=\"text/css\">\n      body {\n        font: 16px Arial;\n        color: #333;\n      }\n    </style>\n    <script type=\"text/javascript\" src=\"chrome_ex_oauthsimple.js\"></script>\n    <script type=\"text/javascript\" src=\"chrome_ex_oauth.js\"></script>\n    <script type=\"text/javascript\">\n      function onLoad() {\n        ChromeExOAuth.initCallbackPage();\n      };\n    </script>\n  </head>\n  <body onload=\"onLoad();\">\n    Redirecting...\n  </body>\n</html>\n"
  },
  {
    "path": "src/chrome_ex_oauth.js",
    "content": "/**\n * Copyright (c) 2010 The Chromium Authors. All rights reserved.  Use of this\n * source code is governed by a BSD-style license that can be found in the\n * LICENSE file.\n */\n\n/**\n * Constructor - no need to invoke directly, call initBackgroundPage instead.\n * @constructor\n * @param {String} url_request_token The OAuth request token URL.\n * @param {String} url_auth_token The OAuth authorize token URL.\n * @param {String} url_access_token The OAuth access token URL.\n * @param {String} consumer_key The OAuth consumer key.\n * @param {String} consumer_secret The OAuth consumer secret.\n * @param {String} oauth_scope The OAuth scope parameter.\n * @param {Object} opt_args Optional arguments.  Recognized parameters:\n *     \"app_name\" {String} Name of the current application\n *     \"callback_page\" {String} If you renamed chrome_ex_oauth.html, the name\n *          this file was renamed to.\n */\nfunction ChromeExOAuth(url_request_token, url_auth_token, url_access_token,\n                       consumer_key, consumer_secret, oauth_scope, opt_args) {\n  this.url_request_token = url_request_token;\n  this.url_auth_token = url_auth_token;\n  this.url_access_token = url_access_token;\n  this.consumer_key = consumer_key;\n  this.consumer_secret = consumer_secret;\n  this.oauth_scope = oauth_scope;\n  this.app_name = opt_args && opt_args['app_name'] ||\n      \"ChromeExOAuth Library\";\n  this.key_token = \"oauth_token\";\n  this.key_token_secret = \"oauth_token_secret\";\n  this.callback_page = opt_args && opt_args['callback_page'] ||\n      \"chrome_ex_oauth.html\";\n  this.auth_params = {};\n  if (opt_args && opt_args['auth_params']) {\n    for (key in opt_args['auth_params']) {\n      if (opt_args['auth_params'].hasOwnProperty(key)) {\n        this.auth_params[key] = opt_args['auth_params'][key];\n      }\n    }\n  }\n};\n\n/*******************************************************************************\n * PUBLIC API METHODS\n * Call these from your background page.\n ******************************************************************************/\n\n/**\n * Initializes the OAuth helper from the background page.  You must call this\n * before attempting to make any OAuth calls.\n * @param {Object} oauth_config Configuration parameters in a JavaScript object.\n *     The following parameters are recognized:\n *         \"request_url\" {String} OAuth request token URL.\n *         \"authorize_url\" {String} OAuth authorize token URL.\n *         \"access_url\" {String} OAuth access token URL.\n *         \"consumer_key\" {String} OAuth consumer key.\n *         \"consumer_secret\" {String} OAuth consumer secret.\n *         \"scope\" {String} OAuth access scope.\n *         \"app_name\" {String} Application name.\n *         \"auth_params\" {Object} Additional parameters to pass to the\n *             Authorization token URL.  For an example, 'hd', 'hl', 'btmpl':\n *             http://code.google.com/apis/accounts/docs/OAuth_ref.html#GetAuth\n * @return {ChromeExOAuth} An initialized ChromeExOAuth object.\n */\nChromeExOAuth.initBackgroundPage = function(oauth_config) {\n  window.chromeExOAuthConfig = oauth_config;\n  window.chromeExOAuth = ChromeExOAuth.fromConfig(oauth_config);\n  window.chromeExOAuthRedirectStarted = false;\n  window.chromeExOAuthRequestingAccess = false;\n\n  var url_match = chrome.extension.getURL(window.chromeExOAuth.callback_page);\n  var tabs = {};\n  chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {\n    if (changeInfo.url &&\n        changeInfo.url.substr(0, url_match.length) === url_match &&\n        changeInfo.url != tabs[tabId] &&\n        window.chromeExOAuthRequestingAccess == false) {\n      chrome.tabs.create({ 'url' : changeInfo.url }, function(tab) {\n        tabs[tab.id] = tab.url;\n        chrome.tabs.remove(tabId);\n      });\n    }\n  });\n\n  return window.chromeExOAuth;\n};\n\n/**\n * Authorizes the current user with the configued API.  You must call this\n * before calling sendSignedRequest.\n * @param {Function} callback A function to call once an access token has\n *     been obtained.  This callback will be passed the following arguments:\n *         token {String} The OAuth access token.\n *         secret {String} The OAuth access token secret.\n */\nChromeExOAuth.prototype.authorize = function(callback) {\n  if (this.hasToken()) {\n    callback(this.getToken(), this.getTokenSecret());\n  } else {\n    window.chromeExOAuthOnAuthorize = function(token, secret) {\n      callback(token, secret);\n    };\n    chrome.tabs.create({ 'url' :chrome.extension.getURL(this.callback_page) });\n  }\n};\n\n/**\n * Clears any OAuth tokens stored for this configuration.  Effectively a\n * \"logout\" of the configured OAuth API.\n */\nChromeExOAuth.prototype.clearTokens = function() {\n  delete localStorage[this.key_token + encodeURI(this.oauth_scope)];\n  delete localStorage[this.key_token_secret + encodeURI(this.oauth_scope)];\n};\n\n/**\n * Returns whether a token is currently stored for this configuration.\n * Effectively a check to see whether the current user is \"logged in\" to\n * the configured OAuth API.\n * @return {Boolean} True if an access token exists.\n */\nChromeExOAuth.prototype.hasToken = function() {\n  return !!this.getToken();\n};\n\n/**\n * Makes an OAuth-signed HTTP request with the currently authorized tokens.\n * @param {String} url The URL to send the request to.  Querystring parameters\n *     should be omitted.\n * @param {Function} callback A function to be called once the request is\n *     completed.  This callback will be passed the following arguments:\n *         responseText {String} The text response.\n *         xhr {XMLHttpRequest} The XMLHttpRequest object which was used to\n *             send the request.  Useful if you need to check response status\n *             code, etc.\n * @param {Object} opt_params Additional parameters to configure the request.\n *     The following parameters are accepted:\n *         \"method\" {String} The HTTP method to use.  Defaults to \"GET\".\n *         \"body\" {String} A request body to send.  Defaults to null.\n *         \"parameters\" {Object} Query parameters to include in the request.\n *         \"headers\" {Object} Additional headers to include in the request.\n */\nChromeExOAuth.prototype.sendSignedRequest = function(url, callback,\n                                                     opt_params) {\n  var method = opt_params && opt_params['method'] || 'GET';\n  var body = opt_params && opt_params['body'] || null;\n  var params = opt_params && opt_params['parameters'] || {};\n  var headers = opt_params && opt_params['headers'] || {};\n\n  var signedUrl = this.signURL(url, method, params);\n\n  ChromeExOAuth.sendRequest(method, signedUrl, headers, body, function (xhr) {\n    if (xhr.readyState == 4) {\n      callback(xhr.responseText, xhr);\n    }\n  });\n};\n\n/**\n * Adds the required OAuth parameters to the given url and returns the\n * result.  Useful if you need a signed url but don't want to make an XHR\n * request.\n * @param {String} method The http method to use.\n * @param {String} url The base url of the resource you are querying.\n * @param {Object} opt_params Query parameters to include in the request.\n * @return {String} The base url plus any query params plus any OAuth params.\n */\nChromeExOAuth.prototype.signURL = function(url, method, opt_params) {\n  var token = this.getToken();\n  var secret = this.getTokenSecret();\n  if (!token || !secret) {\n    throw new Error(\"No oauth token or token secret\");\n  }\n\n  var params = opt_params || {};\n\n  var result = OAuthSimple().sign({\n    action : method,\n    path : url,\n    parameters : params,\n    signatures: {\n      consumer_key : this.consumer_key,\n      shared_secret : this.consumer_secret,\n      oauth_secret : secret,\n      oauth_token: token\n    }\n  });\n\n  return result.signed_url;\n};\n\n/**\n * Generates the Authorization header based on the oauth parameters.\n * @param {String} url The base url of the resource you are querying.\n * @param {Object} opt_params Query parameters to include in the request.\n * @return {String} An Authorization header containing the oauth_* params.\n */\nChromeExOAuth.prototype.getAuthorizationHeader = function(url, method,\n                                                          opt_params) {\n  var token = this.getToken();\n  var secret = this.getTokenSecret();\n  if (!token || !secret) {\n    throw new Error(\"No oauth token or token secret\");\n  }\n\n  var params = opt_params || {};\n\n  return OAuthSimple().getHeaderString({\n    action: method,\n    path : url,\n    parameters : params,\n    signatures: {\n      consumer_key : this.consumer_key,\n      shared_secret : this.consumer_secret,\n      oauth_secret : secret,\n      oauth_token: token\n    }\n  });\n};\n\n/*******************************************************************************\n * PRIVATE API METHODS\n * Used by the library.  There should be no need to call these methods directly.\n ******************************************************************************/\n\n/**\n * Creates a new ChromeExOAuth object from the supplied configuration object.\n * @param {Object} oauth_config Configuration parameters in a JavaScript object.\n *     The following parameters are recognized:\n *         \"request_url\" {String} OAuth request token URL.\n *         \"authorize_url\" {String} OAuth authorize token URL.\n *         \"access_url\" {String} OAuth access token URL.\n *         \"consumer_key\" {String} OAuth consumer key.\n *         \"consumer_secret\" {String} OAuth consumer secret.\n *         \"scope\" {String} OAuth access scope.\n *         \"app_name\" {String} Application name.\n *         \"auth_params\" {Object} Additional parameters to pass to the\n *             Authorization token URL.  For an example, 'hd', 'hl', 'btmpl':\n *             http://code.google.com/apis/accounts/docs/OAuth_ref.html#GetAuth\n * @return {ChromeExOAuth} An initialized ChromeExOAuth object.\n */\nChromeExOAuth.fromConfig = function(oauth_config) {\n  return new ChromeExOAuth(\n    oauth_config['request_url'],\n    oauth_config['authorize_url'],\n    oauth_config['access_url'],\n    oauth_config['consumer_key'],\n    oauth_config['consumer_secret'],\n    oauth_config['scope'],\n    {\n      'app_name' : oauth_config['app_name'],\n      'auth_params' : oauth_config['auth_params']\n    }\n  );\n};\n\n/**\n * Initializes chrome_ex_oauth.html and redirects the page if needed to start\n * the OAuth flow.  Once an access token is obtained, this function closes\n * chrome_ex_oauth.html.\n */\nChromeExOAuth.initCallbackPage = function() {\n  var background_page = chrome.extension.getBackgroundPage();\n  var oauth_config = background_page.chromeExOAuthConfig;\n  var oauth = ChromeExOAuth.fromConfig(oauth_config);\n  background_page.chromeExOAuthRedirectStarted = true;\n  oauth.initOAuthFlow(function (token, secret) {\n    background_page.chromeExOAuthOnAuthorize(token, secret);\n    background_page.chromeExOAuthRedirectStarted = false;\n    chrome.tabs.getSelected(null, function (tab) {\n      chrome.tabs.remove(tab.id);\n    });\n  });\n};\n\n/**\n * Sends an HTTP request.  Convenience wrapper for XMLHttpRequest calls.\n * @param {String} method The HTTP method to use.\n * @param {String} url The URL to send the request to.\n * @param {Object} headers Optional request headers in key/value format.\n * @param {String} body Optional body content.\n * @param {Function} callback Function to call when the XMLHttpRequest's\n *     ready state changes.  See documentation for XMLHttpRequest's\n *     onreadystatechange handler for more information.\n */\nChromeExOAuth.sendRequest = function(method, url, headers, body, callback) {\n  var xhr = new XMLHttpRequest();\n  xhr.onreadystatechange = function(data) {\n    callback(xhr, data);\n  }\n  xhr.open(method, url, true);\n  if (headers) {\n    for (var header in headers) {\n      if (headers.hasOwnProperty(header)) {\n        xhr.setRequestHeader(header, headers[header]);\n      }\n    }\n  }\n  xhr.send(body);\n};\n\n/**\n * Decodes a URL-encoded string into key/value pairs.\n * @param {String} encoded An URL-encoded string.\n * @return {Object} An object representing the decoded key/value pairs found\n *     in the encoded string.\n */\nChromeExOAuth.formDecode = function(encoded) {\n  var params = encoded.split(\"&\");\n  var decoded = {};\n  for (var i = 0, param; param = params[i]; i++) {\n    var keyval = param.split(\"=\");\n    if (keyval.length == 2) {\n      var key = ChromeExOAuth.fromRfc3986(keyval[0]);\n      var val = ChromeExOAuth.fromRfc3986(keyval[1]);\n      decoded[key] = val;\n    }\n  }\n  return decoded;\n};\n\n/**\n * Returns the current window's querystring decoded into key/value pairs.\n * @return {Object} A object representing any key/value pairs found in the\n *     current window's querystring.\n */\nChromeExOAuth.getQueryStringParams = function() {\n  var urlparts = window.location.href.split(\"?\");\n  if (urlparts.length >= 2) {\n    var querystring = urlparts.slice(1).join(\"?\");\n    return ChromeExOAuth.formDecode(querystring);\n  }\n  return {};\n};\n\n/**\n * Binds a function call to a specific object.  This function will also take\n * a variable number of additional arguments which will be prepended to the\n * arguments passed to the bound function when it is called.\n * @param {Function} func The function to bind.\n * @param {Object} obj The object to bind to the function's \"this\".\n * @return {Function} A closure that will call the bound function.\n */\nChromeExOAuth.bind = function(func, obj) {\n  var newargs = Array.prototype.slice.call(arguments).slice(2);\n  return function() {\n    var combinedargs = newargs.concat(Array.prototype.slice.call(arguments));\n    func.apply(obj, combinedargs);\n  };\n};\n\n/**\n * Encodes a value according to the RFC3986 specification.\n * @param {String} val The string to encode.\n */\nChromeExOAuth.toRfc3986 = function(val){\n   return encodeURIComponent(val)\n       .replace(/\\!/g, \"%21\")\n       .replace(/\\*/g, \"%2A\")\n       .replace(/'/g, \"%27\")\n       .replace(/\\(/g, \"%28\")\n       .replace(/\\)/g, \"%29\");\n};\n\n/**\n * Decodes a string that has been encoded according to RFC3986.\n * @param {String} val The string to decode.\n */\nChromeExOAuth.fromRfc3986 = function(val){\n  var tmp = val\n      .replace(/%21/g, \"!\")\n      .replace(/%2A/g, \"*\")\n      .replace(/%27/g, \"'\")\n      .replace(/%28/g, \"(\")\n      .replace(/%29/g, \")\");\n   return decodeURIComponent(tmp);\n};\n\n/**\n * Adds a key/value parameter to the supplied URL.\n * @param {String} url An URL which may or may not contain querystring values.\n * @param {String} key A key\n * @param {String} value A value\n * @return {String} The URL with URL-encoded versions of the key and value\n *     appended, prefixing them with \"&\" or \"?\" as needed.\n */\nChromeExOAuth.addURLParam = function(url, key, value) {\n  var sep = (url.indexOf('?') >= 0) ? \"&\" : \"?\";\n  return url + sep +\n         ChromeExOAuth.toRfc3986(key) + \"=\" + ChromeExOAuth.toRfc3986(value);\n};\n\n/**\n * Stores an OAuth token for the configured scope.\n * @param {String} token The token to store.\n */\nChromeExOAuth.prototype.setToken = function(token) {\n  localStorage[this.key_token + encodeURI(this.oauth_scope)] = token;\n};\n\n/**\n * Retrieves any stored token for the configured scope.\n * @return {String} The stored token.\n */\nChromeExOAuth.prototype.getToken = function() {\n  return localStorage[this.key_token + encodeURI(this.oauth_scope)];\n};\n\n/**\n * Stores an OAuth token secret for the configured scope.\n * @param {String} secret The secret to store.\n */\nChromeExOAuth.prototype.setTokenSecret = function(secret) {\n  localStorage[this.key_token_secret + encodeURI(this.oauth_scope)] = secret;\n};\n\n/**\n * Retrieves any stored secret for the configured scope.\n * @return {String} The stored secret.\n */\nChromeExOAuth.prototype.getTokenSecret = function() {\n  return localStorage[this.key_token_secret + encodeURI(this.oauth_scope)];\n};\n\n/**\n * Starts an OAuth authorization flow for the current page.  If a token exists,\n * no redirect is needed and the supplied callback is called immediately.\n * If this method detects that a redirect has finished, it grabs the\n * appropriate OAuth parameters from the URL and attempts to retrieve an\n * access token.  If no token exists and no redirect has happened, then\n * an access token is requested and the page is ultimately redirected.\n * @param {Function} callback The function to call once the flow has finished.\n *     This callback will be passed the following arguments:\n *         token {String} The OAuth access token.\n *         secret {String} The OAuth access token secret.\n */\nChromeExOAuth.prototype.initOAuthFlow = function(callback) {\n  if (!this.hasToken()) {\n    var params = ChromeExOAuth.getQueryStringParams();\n    if (params['chromeexoauthcallback'] == 'true') {\n      var oauth_token = params['oauth_token'];\n      var oauth_verifier = params['oauth_verifier']\n      this.getAccessToken(oauth_token, oauth_verifier, callback);\n    } else {\n      var request_params = {\n        'url_callback_param' : 'chromeexoauthcallback'\n      }\n      this.getRequestToken(function(url) {\n        window.location.href = url;\n      }, request_params);\n    }\n  } else {\n    callback(this.getToken(), this.getTokenSecret());\n  }\n};\n\n/**\n * Requests an OAuth request token.\n * @param {Function} callback Function to call once the authorize URL is\n *     calculated.  This callback will be passed the following arguments:\n *         url {String} The URL the user must be redirected to in order to\n *             approve the token.\n * @param {Object} opt_args Optional arguments.  The following parameters\n *     are accepted:\n *         \"url_callback\" {String} The URL the OAuth provider will redirect to.\n *         \"url_callback_param\" {String} A parameter to include in the callback\n *             URL in order to indicate to this library that a redirect has\n *             taken place.\n */\nChromeExOAuth.prototype.getRequestToken = function(callback, opt_args) {\n  if (typeof callback !== \"function\") {\n    throw new Error(\"Specified callback must be a function.\");\n  }\n  var url = opt_args && opt_args['url_callback'] ||\n            window && window.top && window.top.location &&\n            window.top.location.href;\n\n  var url_param = opt_args && opt_args['url_callback_param'] ||\n                  \"chromeexoauthcallback\";\n  var url_callback = ChromeExOAuth.addURLParam(url, url_param, \"true\");\n\n  var result = OAuthSimple().sign({\n    path : this.url_request_token,\n    parameters: {\n      \"xoauth_displayname\" : this.app_name,\n      \"scope\" : this.oauth_scope,\n      \"oauth_callback\" : url_callback\n    },\n    signatures: {\n      consumer_key : this.consumer_key,\n      shared_secret : this.consumer_secret\n    }\n  });\n  var onToken = ChromeExOAuth.bind(this.onRequestToken, this, callback);\n  ChromeExOAuth.sendRequest(\"GET\", result.signed_url, null, null, onToken);\n};\n\n/**\n * Called when a request token has been returned.  Stores the request token\n * secret for later use and sends the authorization url to the supplied\n * callback (for redirecting the user).\n * @param {Function} callback Function to call once the authorize URL is\n *     calculated.  This callback will be passed the following arguments:\n *         url {String} The URL the user must be redirected to in order to\n *             approve the token.\n * @param {XMLHttpRequest} xhr The XMLHttpRequest object used to fetch the\n *     request token.\n */\nChromeExOAuth.prototype.onRequestToken = function(callback, xhr) {\n  if (xhr.readyState == 4) {\n    if (xhr.status == 200) {\n      var params = ChromeExOAuth.formDecode(xhr.responseText);\n      var token = params['oauth_token'];\n      this.setTokenSecret(params['oauth_token_secret']);\n      var url = ChromeExOAuth.addURLParam(this.url_auth_token,\n                                          \"oauth_token\", token);\n      for (var key in this.auth_params) {\n        if (this.auth_params.hasOwnProperty(key)) {\n          url = ChromeExOAuth.addURLParam(url, key, this.auth_params[key]);\n        }\n      }\n      callback(url);\n    } else {\n      throw new Error(\"Fetching request token failed. Status \" + xhr.status);\n    }\n  }\n};\n\n/**\n * Requests an OAuth access token.\n * @param {String} oauth_token The OAuth request token.\n * @param {String} oauth_verifier The OAuth token verifier.\n * @param {Function} callback The function to call once the token is obtained.\n *     This callback will be passed the following arguments:\n *         token {String} The OAuth access token.\n *         secret {String} The OAuth access token secret.\n */\nChromeExOAuth.prototype.getAccessToken = function(oauth_token, oauth_verifier,\n                                                  callback) {\n  if (typeof callback !== \"function\") {\n    throw new Error(\"Specified callback must be a function.\");\n  }\n  var bg = chrome.extension.getBackgroundPage();\n  if (bg.chromeExOAuthRequestingAccess == false) {\n    bg.chromeExOAuthRequestingAccess = true;\n\n    var result = OAuthSimple().sign({\n      path : this.url_access_token,\n      parameters: {\n        \"oauth_token\" : oauth_token,\n        \"oauth_verifier\" : oauth_verifier\n      },\n      signatures: {\n        consumer_key : this.consumer_key,\n        shared_secret : this.consumer_secret,\n        oauth_secret : this.getTokenSecret(this.oauth_scope)\n      }\n    });\n\n    var onToken = ChromeExOAuth.bind(this.onAccessToken, this, callback);\n    ChromeExOAuth.sendRequest(\"GET\", result.signed_url, null, null, onToken);\n  }\n};\n\n/**\n * Called when an access token has been returned.  Stores the access token and\n * access token secret for later use and sends them to the supplied callback.\n * @param {Function} callback The function to call once the token is obtained.\n *     This callback will be passed the following arguments:\n *         token {String} The OAuth access token.\n *         secret {String} The OAuth access token secret.\n * @param {XMLHttpRequest} xhr The XMLHttpRequest object used to fetch the\n *     access token.\n */\nChromeExOAuth.prototype.onAccessToken = function(callback, xhr) {\n  if (xhr.readyState == 4) {\n    var bg = chrome.extension.getBackgroundPage();\n    if (xhr.status == 200) {\n      var params = ChromeExOAuth.formDecode(xhr.responseText);\n      var token = params[\"oauth_token\"];\n      var secret = params[\"oauth_token_secret\"];\n      this.setToken(token);\n      this.setTokenSecret(secret);\n      bg.chromeExOAuthRequestingAccess = false;\n      callback(token, secret);\n    } else {\n      bg.chromeExOAuthRequestingAccess = false;\n      throw new Error(\"Fetching access token failed with status \" + xhr.status);\n    }\n  }\n};"
  },
  {
    "path": "src/chrome_ex_oauthsimple.js",
    "content": "/* OAuthSimple\n  * A simpler version of OAuth\n  *\n  * author:     jr conlin\n  * mail:       src@anticipatr.com\n  * copyright:  unitedHeroes.net\n  * version:    1.0\n  * url:        http://unitedHeroes.net/OAuthSimple\n  *\n  * Copyright (c) 2009, unitedHeroes.net\n  * All rights reserved.\n  *\n  * Redistribution and use in source and binary forms, with or without\n  * modification, are permitted provided that the following conditions are met:\n  *     * Redistributions of source code must retain the above copyright\n  *       notice, this list of conditions and the following disclaimer.\n  *     * Redistributions in binary form must reproduce the above copyright\n  *       notice, this list of conditions and the following disclaimer in the\n  *       documentation and/or other materials provided with the distribution.\n  *     * Neither the name of the unitedHeroes.net nor the\n  *       names of its contributors may be used to endorse or promote products\n  *       derived from this software without specific prior written permission.\n  *\n  * THIS SOFTWARE IS PROVIDED BY UNITEDHEROES.NET ''AS IS'' AND ANY\n  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n  * DISCLAIMED. IN NO EVENT SHALL UNITEDHEROES.NET BE LIABLE FOR ANY\n  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\nvar OAuthSimple;\n\nif (OAuthSimple === undefined)\n{\n    /* Simple OAuth\n     *\n     * This class only builds the OAuth elements, it does not do the actual\n     * transmission or reception of the tokens. It does not validate elements\n     * of the token. It is for client use only.\n     *\n     * api_key is the API key, also known as the OAuth consumer key\n     * shared_secret is the shared secret (duh).\n     *\n     * Both the api_key and shared_secret are generally provided by the site\n     * offering OAuth services. You need to specify them at object creation\n     * because nobody <explative>ing uses OAuth without that minimal set of\n     * signatures.\n     *\n     * If you want to use the higher order security that comes from the\n     * OAuth token (sorry, I don't provide the functions to fetch that because\n     * sites aren't horribly consistent about how they offer that), you need to\n     * pass those in either with .setTokensAndSecrets() or as an argument to the\n     * .sign() or .getHeaderString() functions.\n     *\n     * Example:\n       <code>\n        var oauthObject = OAuthSimple().sign({path:'http://example.com/rest/',\n                                              parameters: 'foo=bar&gorp=banana',\n                                              signatures:{\n                                                api_key:'12345abcd',\n                                                shared_secret:'xyz-5309'\n                                             }});\n        document.getElementById('someLink').href=oauthObject.signed_url;\n       </code>\n     *\n     * that will sign as a \"GET\" using \"SHA1-MAC\" the url. If you need more than\n     * that, read on, McDuff.\n     */\n\n    /** OAuthSimple creator\n     *\n     * Create an instance of OAuthSimple\n     *\n     * @param api_key {string}       The API Key (sometimes referred to as the consumer key) This value is usually supplied by the site you wish to use.\n     * @param shared_secret (string) The shared secret. This value is also usually provided by the site you wish to use.\n     */\n    OAuthSimple = function (consumer_key,shared_secret)\n    {\n/*        if (api_key == undefined)\n            throw(\"Missing argument: api_key (oauth_consumer_key) for OAuthSimple. This is usually provided by the hosting site.\");\n        if (shared_secret == undefined)\n            throw(\"Missing argument: shared_secret (shared secret) for OAuthSimple. This is usually provided by the hosting site.\");\n*/      this._secrets={};\n        this._parameters={};\n\n        // General configuration options.\n        if (consumer_key !== undefined) {\n            this._secrets['consumer_key'] = consumer_key;\n            }\n        if (shared_secret !== undefined) {\n            this._secrets['shared_secret'] = shared_secret;\n            }\n        this._default_signature_method= \"HMAC-SHA1\";\n        this._action = \"GET\";\n        this._nonce_chars = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n\n\n        this.reset = function() {\n            this._parameters={};\n            this._path=undefined;\n            return this;\n        };\n\n        /** set the parameters either from a hash or a string\n         *\n         * @param {string,object} List of parameters for the call, this can either be a URI string (e.g. \"foo=bar&gorp=banana\" or an object/hash)\n         */\n        this.setParameters = function (parameters) {\n            if (parameters === undefined) {\n                parameters = {};\n                }\n            if (typeof(parameters) == 'string') {\n                parameters=this._parseParameterString(parameters);\n                }\n            this._parameters = parameters;\n            if (this._parameters['oauth_nonce'] === undefined) {\n                this._getNonce();\n                }\n            if (this._parameters['oauth_timestamp'] === undefined) {\n                this._getTimestamp();\n                }\n            if (this._parameters['oauth_method'] === undefined) {\n                this.setSignatureMethod();\n                }\n            if (this._parameters['oauth_consumer_key'] === undefined) {\n                this._getApiKey();\n                }\n            if(this._parameters['oauth_token'] === undefined) {\n                this._getAccessToken();\n                }\n\n            return this;\n        };\n\n        /** convienence method for setParameters\n         *\n         * @param parameters {string,object} See .setParameters\n         */\n        this.setQueryString = function (parameters) {\n            return this.setParameters(parameters);\n        };\n\n        /** Set the target URL (does not include the parameters)\n         *\n         * @param path {string} the fully qualified URI (excluding query arguments) (e.g \"http://example.org/foo\")\n         */\n        this.setURL = function (path) {\n            if (path == '') {\n                throw ('No path specified for OAuthSimple.setURL');\n                }\n            this._path = path;\n            return this;\n        };\n\n        /** convienence method for setURL\n         *\n         * @param path {string} see .setURL\n         */\n        this.setPath = function(path){\n            return this.setURL(path);\n        };\n\n        /** set the \"action\" for the url, (e.g. GET,POST, DELETE, etc.)\n         *\n         * @param action {string} HTTP Action word.\n         */\n        this.setAction = function(action) {\n            if (action === undefined) {\n                action=\"GET\";\n                }\n            action = action.toUpperCase();\n            if (action.match('[^A-Z]')) {\n                throw ('Invalid action specified for OAuthSimple.setAction');\n                }\n            this._action = action;\n            return this;\n        };\n\n        /** set the signatures (as well as validate the ones you have)\n         *\n         * @param signatures {object} object/hash of the token/signature pairs {api_key:, shared_secret:, oauth_token: oauth_secret:}\n         */\n        this.setTokensAndSecrets = function(signatures) {\n            if (signatures)\n            {\n                for (var i in signatures) {\n                    this._secrets[i] = signatures[i];\n                    }\n            }\n            // Aliases\n            if (this._secrets['api_key']) {\n                this._secrets.consumer_key = this._secrets.api_key;\n                }\n            if (this._secrets['access_token']) {\n                this._secrets.oauth_token = this._secrets.access_token;\n                }\n            if (this._secrets['access_secret']) {\n                this._secrets.oauth_secret = this._secrets.access_secret;\n                }\n            // Gauntlet\n            if (this._secrets.consumer_key === undefined) {\n                throw('Missing required consumer_key in OAuthSimple.setTokensAndSecrets');\n                }\n            if (this._secrets.shared_secret === undefined) {\n                throw('Missing required shared_secret in OAuthSimple.setTokensAndSecrets');\n                }\n            if ((this._secrets.oauth_token !== undefined) && (this._secrets.oauth_secret === undefined)) {\n                throw('Missing oauth_secret for supplied oauth_token in OAuthSimple.setTokensAndSecrets');\n                }\n            return this;\n        };\n\n        /** set the signature method (currently only Plaintext or SHA-MAC1)\n         *\n         * @param method {string} Method of signing the transaction (only PLAINTEXT and SHA-MAC1 allowed for now)\n         */\n        this.setSignatureMethod = function(method) {\n            if (method === undefined) {\n                method = this._default_signature_method;\n                }\n            //TODO: accept things other than PlainText or SHA-MAC1\n            if (method.toUpperCase().match(/(PLAINTEXT|HMAC-SHA1)/) === undefined) {\n                throw ('Unknown signing method specified for OAuthSimple.setSignatureMethod');\n                }\n            this._parameters['oauth_signature_method']= method.toUpperCase();\n            return this;\n        };\n\n        /** sign the request\n         *\n         * note: all arguments are optional, provided you've set them using the\n         * other helper functions.\n         *\n         * @param args {object} hash of arguments for the call\n         *                   {action:, path:, parameters:, method:, signatures:}\n         *                   all arguments are optional.\n         */\n        this.sign = function (args) {\n            if (args === undefined) {\n                args = {};\n                }\n            // Set any given parameters\n            if(args['action'] !== undefined) {\n                this.setAction(args['action']);\n                }\n            if (args['path'] !== undefined) {\n                this.setPath(args['path']);\n                }\n            if (args['method'] !== undefined) {\n                this.setSignatureMethod(args['method']);\n                }\n            this.setTokensAndSecrets(args['signatures']);\n            if (args['parameters'] !== undefined){\n            this.setParameters(args['parameters']);\n            }\n            // check the parameters\n            var normParams = this._normalizedParameters();\n            this._parameters['oauth_signature']=this._generateSignature(normParams);\n            return {\n                parameters: this._parameters,\n                signature: this._oauthEscape(this._parameters['oauth_signature']),\n                signed_url: this._path + '?' + this._normalizedParameters(),\n                header: this.getHeaderString()\n            };\n        };\n\n        /** Return a formatted \"header\" string\n         *\n         * NOTE: This doesn't set the \"Authorization: \" prefix, which is required.\n         * I don't set it because various set header functions prefer different\n         * ways to do that.\n         *\n         * @param args {object} see .sign\n         */\n        this.getHeaderString = function(args) {\n            if (this._parameters['oauth_signature'] === undefined) {\n                this.sign(args);\n                }\n\n            var result = 'OAuth ';\n            for (var pName in this._parameters)\n            {\n                if (!pName.match(/^oauth/)) {\n                    continue;\n                    }\n                if ((this._parameters[pName]) instanceof Array)\n                {\n                    var pLength = this._parameters[pName].length;\n                    for (var j=0;j<pLength;j++)\n                    {\n                        result += pName +'=\"'+this._oauthEscape(this._parameters[pName][j])+'\" ';\n                    }\n                }\n                else\n                {\n                    result += pName + '=\"'+this._oauthEscape(this._parameters[pName])+'\" ';\n                }\n            }\n            return result;\n        };\n\n        // Start Private Methods.\n\n        /** convert the parameter string into a hash of objects.\n         *\n         */\n        this._parseParameterString = function(paramString){\n            var elements = paramString.split('&');\n            var result={};\n            for(var element=elements.shift();element;element=elements.shift())\n            {\n                var keyToken=element.split('=');\n                var value='';\n                if (keyToken[1]) {\n                    value=decodeURIComponent(keyToken[1]);\n                    }\n                if(result[keyToken[0]]){\n                    if (!(result[keyToken[0]] instanceof Array))\n                    {\n                        result[keyToken[0]] = Array(result[keyToken[0]],value);\n                    }\n                    else\n                    {\n                        result[keyToken[0]].push(value);\n                    }\n                }\n                else\n                {\n                    result[keyToken[0]]=value;\n                }\n            }\n            return result;\n        };\n\n        this._oauthEscape = function(string) {\n            if (string === undefined) {\n                return \"\";\n                }\n            if (string instanceof Array)\n            {\n                throw('Array passed to _oauthEscape');\n            }\n            return encodeURIComponent(string).replace(/\\!/g, \"%21\").\n            replace(/\\*/g, \"%2A\").\n            replace(/'/g, \"%27\").\n            replace(/\\(/g, \"%28\").\n            replace(/\\)/g, \"%29\");\n        };\n\n        this._getNonce = function (length) {\n            if (length === undefined) {\n                length=5;\n                }\n            var result = \"\";\n            var cLength = this._nonce_chars.length;\n            for (var i = 0; i < length;i++) {\n                var rnum = Math.floor(Math.random() *cLength);\n                result += this._nonce_chars.substring(rnum,rnum+1);\n            }\n            this._parameters['oauth_nonce']=result;\n            return result;\n        };\n\n        this._getApiKey = function() {\n            if (this._secrets.consumer_key === undefined) {\n                throw('No consumer_key set for OAuthSimple.');\n                }\n            this._parameters['oauth_consumer_key']=this._secrets.consumer_key;\n            return this._parameters.oauth_consumer_key;\n        };\n\n        this._getAccessToken = function() {\n            if (this._secrets['oauth_secret'] === undefined) {\n                return '';\n                }\n            if (this._secrets['oauth_token'] === undefined) {\n                throw('No oauth_token (access_token) set for OAuthSimple.');\n                }\n            this._parameters['oauth_token'] = this._secrets.oauth_token;\n            return this._parameters.oauth_token;\n        };\n\n        this._getTimestamp = function() {\n            var d = new Date();\n            var ts = Math.floor(d.getTime()/1000);\n            this._parameters['oauth_timestamp'] = ts;\n            return ts;\n        };\n\n        this.b64_hmac_sha1 = function(k,d,_p,_z){\n        // heavily optimized and compressed version of http://pajhome.org.uk/crypt/md5/sha1.js\n        // _p = b64pad, _z = character size; not used here but I left them available just in case\n        if(!_p){_p='=';}if(!_z){_z=8;}function _f(t,b,c,d){if(t<20){return(b&c)|((~b)&d);}if(t<40){return b^c^d;}if(t<60){return(b&c)|(b&d)|(c&d);}return b^c^d;}function _k(t){return(t<20)?1518500249:(t<40)?1859775393:(t<60)?-1894007588:-899497514;}function _s(x,y){var l=(x&0xFFFF)+(y&0xFFFF),m=(x>>16)+(y>>16)+(l>>16);return(m<<16)|(l&0xFFFF);}function _r(n,c){return(n<<c)|(n>>>(32-c));}function _c(x,l){x[l>>5]|=0x80<<(24-l%32);x[((l+64>>9)<<4)+15]=l;var w=[80],a=1732584193,b=-271733879,c=-1732584194,d=271733878,e=-1009589776;for(var i=0;i<x.length;i+=16){var o=a,p=b,q=c,r=d,s=e;for(var j=0;j<80;j++){if(j<16){w[j]=x[i+j];}else{w[j]=_r(w[j-3]^w[j-8]^w[j-14]^w[j-16],1);}var t=_s(_s(_r(a,5),_f(j,b,c,d)),_s(_s(e,w[j]),_k(j)));e=d;d=c;c=_r(b,30);b=a;a=t;}a=_s(a,o);b=_s(b,p);c=_s(c,q);d=_s(d,r);e=_s(e,s);}return[a,b,c,d,e];}function _b(s){var b=[],m=(1<<_z)-1;for(var i=0;i<s.length*_z;i+=_z){b[i>>5]|=(s.charCodeAt(i/8)&m)<<(32-_z-i%32);}return b;}function _h(k,d){var b=_b(k);if(b.length>16){b=_c(b,k.length*_z);}var p=[16],o=[16];for(var i=0;i<16;i++){p[i]=b[i]^0x36363636;o[i]=b[i]^0x5C5C5C5C;}var h=_c(p.concat(_b(d)),512+d.length*_z);return _c(o.concat(h),512+160);}function _n(b){var t=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\",s='';for(var i=0;i<b.length*4;i+=3){var r=(((b[i>>2]>>8*(3-i%4))&0xFF)<<16)|(((b[i+1>>2]>>8*(3-(i+1)%4))&0xFF)<<8)|((b[i+2>>2]>>8*(3-(i+2)%4))&0xFF);for(var j=0;j<4;j++){if(i*8+j*6>b.length*32){s+=_p;}else{s+=t.charAt((r>>6*(3-j))&0x3F);}}}return s;}function _x(k,d){return _n(_h(k,d));}return _x(k,d);\n        }\n\n\n        this._normalizedParameters = function() {\n            var elements = new Array();\n            var paramNames = [];\n            var ra =0;\n            for (var paramName in this._parameters)\n            {\n                if (ra++ > 1000) {\n                    throw('runaway 1');\n                    }\n                paramNames.unshift(paramName);\n            }\n            paramNames = paramNames.sort();\n            pLen = paramNames.length;\n            for (var i=0;i<pLen; i++)\n            {\n                paramName=paramNames[i];\n                //skip secrets.\n                if (paramName.match(/\\w+_secret/)) {\n                    continue;\n                    }\n                if (this._parameters[paramName] instanceof Array)\n                {\n                    var sorted = this._parameters[paramName].sort();\n                    var spLen = sorted.length;\n                    for (var j = 0;j<spLen;j++){\n                        if (ra++ > 1000) {\n                            throw('runaway 1');\n                            }\n                        elements.push(this._oauthEscape(paramName) + '=' +\n                                  this._oauthEscape(sorted[j]));\n                    }\n                    continue;\n                }\n                elements.push(this._oauthEscape(paramName) + '=' +\n                              this._oauthEscape(this._parameters[paramName]));\n            }\n            return elements.join('&');\n        };\n\n        this._generateSignature = function() {\n\n            var secretKey = this._oauthEscape(this._secrets.shared_secret)+'&'+\n                this._oauthEscape(this._secrets.oauth_secret);\n            if (this._parameters['oauth_signature_method'] == 'PLAINTEXT')\n            {\n                return secretKey;\n            }\n            if (this._parameters['oauth_signature_method'] == 'HMAC-SHA1')\n            {\n                var sigString = this._oauthEscape(this._action)+'&'+this._oauthEscape(this._path)+'&'+this._oauthEscape(this._normalizedParameters());\n                return this.b64_hmac_sha1(secretKey,sigString);\n            }\n            return null;\n        };\n\n    return this;\n    };\n}\n"
  },
  {
    "path": "src/css/base.css",
    "content": "html, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, font, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td {\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\toutline: 0;\n\tfont-size: 100%;\n\tvertical-align: baseline;\n\tbackground: transparent;\n}\nbody {\n\tline-height: 1;\n  font-family: \"Lucida Grande\",Arial,sans-serif;\n  font-size: 10px;\n  color: #333;\n}\nol, ul {\n\tlist-style: none;\n}\nblockquote, q {\n\tquotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n\tcontent: '';\n\tcontent: none;\n}\n:focus {\n\toutline: 0;\n}\nins {\n\ttext-decoration: none;\n}\ndel {\n\ttext-decoration: line-through;\n}\ntable {\n\tborder-collapse: collapse;\n\tborder-spacing: 0;\n}\np {\n  margin-bottom: 1em;\n  line-height: 1.5;\n}\na {\n  color: #4492D7;\n  text-decoration: none;\n}\na:hover {\n  text-decoration: underline;\n}\n\n.disabled {\n  color: #aaa;\n}\n\na.button, button, input[type=submit] {\n  outline: none;\n  border: 1px solid #aaa;\n  padding: 7px 10px;\n  border-radius: 5px;    \n  background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ddd));\n  color: #333;\n  text-shadow: 0 1px rgba(255,255,255,0.8);\n  text-decoration: none;\n  font-size: 11px;\n}\n\na.button:active, button:active, input[type=submit]:active {\n  background: -webkit-gradient(linear, left top, left bottom, from(#ddd), to(#eee));\n}\n\na.button:focus, button:focus, input[type=submit]:focus {\n  border-color: #999;\n  -webkit-box-shadow: 0 0 3px rgba(0,0,0,0.3);\n}\n\nselect {\n  border: 1px solid #aaa;\n  padding: 3px;\n}\n"
  },
  {
    "path": "src/css/popup.css",
    "content": "@import url('base.css');\n\nhtml {\n  width: 300px;\n}\n\nbody {\n  margin: 10px;\n  padding: 0;\n}\n\n#presets {\n  margin: 0;\n  overflow: auto;\n  max-height: 300px;\n}\n\n  #presets li {\n    list-style: none;\n    margin: 0;\n  }\n  \n  #presets .preset a {\n    color: #333;\n    display: block;\n    text-decoration: none;\n    padding: 10px;\n    padding-left: 31px;\n    background-image: url('../img/application-form.png');\n    background-repeat: no-repeat;\n    background-position: 10px;\n  }\n  \n  #presets .preset a:focus {\n    outline: none;\n  }\n  \n  #presets .preset:hover {\n    background-color: #eee;\n    text-decoration: underline;\n  }\n  \n#footer {\n  margin-top: 10px;\n  padding-top: 10px;\n  text-align: right;\n  border-top: 1px solid #999;\n}\n\n  #scraper {\n    float: left;\n    text-decoration: none;\n    font-weight: bold;\n    color: #333;\n  }"
  },
  {
    "path": "src/css/viewer.css",
    "content": "@import url('base.css');\n\nbody {\n  font-family: \"Lucida Grande\",Arial,sans-serif;\n  font-size: 10px;\n  margin: 0;\n  padding: 0;\n}\n\na:focus {\n  outline: none;\n}\n\ndiv.error {\n  line-height: 1.5;\n}\n\ndiv.error.ui-dialog-content.ui-widget-content {\n  padding-left: 40px;\n  background-repeat: no-repeat;\n  background-position: 12px 12px;\n  background-image: url('../img/exclamation-red.png');\n}\n\n#presets {\n  display: none;\n  padding-top: 10px;\n}\n\n  #presets-form {\n    padding-bottom: 15px;\n  }\n  \n    #presets-form fieldset {\n      margin-top: 10px;\n      padding-top: 5px;\n      border: none;\n      border-top: 1px solid #aaa;\n    }\n  \n    #presets-form-name {\n      width: 70%;\n      border: 1px solid #999;\n      border-radius: 5px;\n      -webkit-box-shadow: inset 1px 2px 3px rgba(0,0,0,0.2);\n      padding: 5px 5px;\n      margin-bottom: 10px;\n    }\n\n  #presets-list {\n    margin: 0;\n    padding: 0;\n    overflow: auto;\n  }\n  \n    #presets-list li {\n      list-style: none;\n      margin: 0;\n      padding: 10px;\n    }\n    \n    #presets-list li a {\n      color: #333;\n    }\n    \n    #presets-list li a:focus {\n      outline: none;\n    }\n    \n    #presets-list li:hover {\n      background-color: #eee;\n    }\n    \n      #presets-list li {\n        padding-right: 26px;\n      }\n    \n      #presets-list li .preset-handle {\n        cursor: move;\n        display: block;\n        float: left;\n      }\n      \n      #presets-list li .preset-load {\n        cursor: pointer;\n        display: block;\n        margin-top: 2px;\n        margin-left: 26px;\n        margin-right: 26px;\n        line-height: 1.5;\n      }\n    \n      #presets-list li .preset-remove {\n        display: inline-block;\n        position: absolute;\n        right: 16px;\n      }\n\n#options {\n  -webkit-user-select: none;\n} \n\n  #options-header {\n    min-height: 30px;\n    border-top: 1px solid #fff !important;\n    background: -webkit-gradient(linear, left bottom, left top, color-stop(0.1, #ccc), color-stop(0.8, #eee));\n    padding: 10px;\n    line-height: 1.2;\n  }\n  \n    #options-meta-page {\n      background-image: url('../img/scraper32.png');\n      background-position: top left;\n      background-repeat: no-repeat;\n      min-height: 32px;\n      padding-left: 42px;\n    }\n    \n    #options-meta-page a {\n      text-decoration: none;\n      color: #444;\n      text-shadow: 0 1px 0 #fff;\n      font-weight: bold;\n      font-size: 120%;\n    }\n\n  #options-center {\n    background-color: #f4f4f4 !important;\n    border-bottom: 1px solid #aaa !important;\n    padding: 10px;\n    border-top: 1px solid #aaa;\n  }\n\n  #options fieldset {\n    margin: 10px 0;\n    border: none;\n    border-top: 1px solid #ccc;\n    padding: 10px;\n  }\n\n  #options fieldset legend {\n    font-weight: bold;\n    color: #333;\n    padding: 0 5px;\n    text-shadow: 0 1px rgba(255,255,255,0.9);\n  }\n\n  #options-selector-table {\n    margin: 0;\n    padding: 0;\n    width: 100%;\n    border-collapse: collapse;\n  }\n\n    #options-selector-table td {\n      padding: 2px 5px;\n    }\n    \n    #options-selector-table select {\n      height: 25px;\n    }\n\n    #options-selector-table input[type=text] {\n      border: 1px solid #999;\n      border-radius: 5px;\n      -webkit-box-shadow: inset 1px 2px 3px rgba(0,0,0,0.2);\n      padding: 5px 5px;\n    }\n\n    #options-language-help a {\n      background-image: url('../img/question-small-white.png');\n      background-repeat: no-repeat;\n      background-position: 0 -2px;\n      padding-left: 20px;\n      min-height: 16px;\n      display: inline-block;\n      vertical-align: middle;\n      color: #666;\n      text-decoration: none;\n    }\n    \n    #options-language-help a:hover {\n      text-decoration: underline;\n    }\n\n    #options-selector {\n      width: 100%;\n    }\n\n  #options-attributes {\n    width: 100%;\n    border-collapse: collapse;\n    border-spacing: 0;\n  }\n\n  #options-attributes tbody td {\n    padding: 4px;\n  }\n\n  #options-attributes thead tr {\n    border: 1px solid #ccc;\n  }\n\n  #options-attributes thead th {\n    background: -webkit-gradient(linear, left bottom, left top, color-stop(0.1, #ccc), color-stop(0.8, #eee));\n    border: none;\n    color: #333;\n    padding: 4px;\n    text-align: left;\n    text-shadow: 0 1px rgba(255,255,255,0.9);\n  }\n\n  #options-attributes .dragHandle {\n    width: 16px;\n    cursor: move;\n    background-image: url('../img/handle.png');\n    background-position: left center;\n    background-repeat: no-repeat;\n  }\n\n  #options-attributes tr.tDnD_whileDrag {\n    opacity: 0.5;\n  }\n\n  #options-attributes tr.tDnD_whileDrag .dragHandle {\n    background-position: left center;\n    background-repeat: no-repeat;\n  }\n\n  #options-attributes input {\n    width: 100%;\n    border: none;\n    border-radius: 0;\n    -webkit-box-shadow: none;\n    padding: 0;\n    background: transparent;\n    padding: 4px 2px;\n  }\n\n  #options-attributes input:focus {\n    border: 1px solid #aaa;\n    padding: 3px 1px;\n    background-color: #fff;\n  }\n\n  #options-attributes img {\n    margin-right: 5px;\n  }\n  \n  #options-presets-select {\n    width: 50%;\n  }\n\n#center {\n  margin-left: 380px;\n  border-top: 1px solid #aaa;\n}\n\n  #results-table {\n    border-bottom: 1px solid #aaa;\n  }\n\n  #results-table table {\n    width: 100%;\n    border-spacing: 0;\n  }\n\n  #results-table table thead {\n    border-bottom: 1px solid #aaa;\n    background: -webkit-gradient(linear, left bottom, left top, color-stop(0.1, #ccc), color-stop(0.8, #eee));\n    color: #333;\n    text-shadow: 0 1px rgba(255,255,255,0.9);\n  }\n\n  #results-table table thead tr {\n    position: relative;\n    top: 0;\n  }\n\n  #results-table table thead th {\n    padding: 5px;\n    border-left: 1px solid #fff;\n    border-right: 1px solid #aaa;\n    border-bottom: 1px solid #aaa;\n    cursor: pointer;\n  }\n\n  #results-table table td {\n    padding: 5px;\n  }\n  \n  #results-table td.tools, #results-table td.index {\n    width: 10px;\n  }\n\n  #results-table table td.tools img {\n    margin-right: 2px;\n    cursor: pointer;\n  }\n\n  #results-table table tr.odd {\n    background-color: #f0f0f0;\n  }\n\n  #results-table table tr:hover td {\n    background-color: #f5f5ff;\n  }\n\n  #export {\n    border-top: 1px solid #fff !important;\n    background: -webkit-gradient(linear, left bottom, left top, color-stop(0.1, #ccc), color-stop(0.8, #eee));\n    padding: 10px;\n    text-align: right;\n    height: 30px;\n  }\n    \n#about {\n  display: none;\n  padding-top: 10px;\n  background-image: url('../img/scraper48.png');\n  background-repeat: no-repeat;\n  background-position: 10px 10px;\n  padding-left: 70px;\n}\n\n  #about h1 {\n    margin: 0;\n    font-size: 200%;\n    font-weight: normal;\n    margin-bottom: 0.2em;\n  }\n\n  #about h2 {\n    font-size: 100%;\n    margin-bottom: 2em;\n  }\n  \n  #about dl {\n    margin-top: 2em;\n  }\n  \n  #about dl dt {\n    font-weight: bold;\n    margin-bottom: 0.5em;\n  }\n  \n  #about dl dd {\n    padding-left: 1em;\n    margin-bottom: 0.5em;\n  }\n  \n  #about a {\n    text-decoration: underline;\n  }\n  \n.pane-footer {\n  height: 30px;\n  border-top: 1px solid #fff !important;\n  background: -webkit-gradient(linear, left bottom, left top, color-stop(0.1, #ccc), color-stop(0.8, #eee));\n  padding: 10px;\n}\n\n  .pane-footer table {\n    width: 100%;\n    margin: 0;\n    padding: 0;\n    border: 0;\n    border-collapse: collapse;\n  }\n\n  .pane-footer table td {\n    margin: 0;\n    padding: 0;\n    text-align: right;\n  }\n\n  .pane-footer table td:first-child {\n    text-align: left;\n  }\n\n\n.ui-corner-all {\n  border-radius: 0;\n}\n\n.ui-tabs {\n  padding: 0;\n}\n\n.ui-state-default a {\n  display: inline-block;\n  vertical-align: top;\n}\n\n.ui-state-default a img {\n  margin-right: 5px;\n}\n\n/*\n *  PANES & CONTENT-DIVs\n */\n.ui-layout-pane {\n  background: #FFF; \n  border:     1px solid #BBB;\n  overflow:   auto;\n}\n\n  .ui-layout-content {\n    position:   relative;\n    overflow:   auto;\n  }\n\n/*\n *  RESIZER-BARS\n */\n.ui-layout-resizer  { /* all 'resizer-bars' */\n    background:     #eee;\n    border-right: 1px solid #ddd !important;\n    border-left: 1px solid #fff !important;\n    border-width:   0;\n    }\n    .ui-layout-resizer-drag {       /* REAL resizer while resize in progress */\n    }\n    .ui-layout-resizer-hover    {   /* affects both open and closed states */\n    }\n    /* NOTE: It looks best when 'hover' and 'dragging' are set to the same color,\n        otherwise color shifts while dragging when bar can't keep up with mouse */\n    .ui-layout-resizer-open-hover , /* hover-color to 'resize' */\n    .ui-layout-resizer-dragging {   /* resizer beging 'dragging' */\n        background: rgba(255,255,255,0.5);\n    }\n    .ui-layout-resizer-dragging {   /* CLONED resizer being dragged */\n      border-right: 1px solid #ddd !important;\n      border-left: 1px solid #fff !important;\n    }\n    /* NOTE: Add a 'dragging-limit' color to provide visual feedback when resizer hits min/max size limits */\n    .ui-layout-resizer-dragging-limit { /* CLONED resizer at min or max size-limit */\n        background: #E1A4A4; /* red */\n    }\n\n    .ui-layout-resizer-closed-hover { /* hover-color to 'slide open' */\n        background: #EBD5AA;\n    }\n    .ui-layout-resizer-sliding {    /* resizer when pane is 'slid open' */\n        opacity: .10; /* show only a slight shadow */\n        filter:  alpha(opacity=10);\n        }\n        .ui-layout-resizer-sliding-hover {  /* sliding resizer - hover */\n            opacity: 1.00; /* on-hover, show the resizer-bar normally */\n            filter:  alpha(opacity=100);\n        }\n        /* sliding resizer - add 'outside-border' to resizer on-hover \n         * this sample illustrates how to target specific panes and states */\n        .ui-layout-resizer-north-sliding-hover  { border-bottom-width:  1px; }\n        .ui-layout-resizer-south-sliding-hover  { border-top-width:     1px; }\n        .ui-layout-resizer-west-sliding-hover   { border-right-width:   1px; }\n        .ui-layout-resizer-east-sliding-hover   { border-left-width:    1px; }\n\n/*\n *  TOGGLER-BUTTONS\n */\n.ui-layout-toggler {\n    border: 1px solid #ddd; /* match pane-border */\n    background-color: #ddd;\n    }\n    .ui-layout-resizer-hover .ui-layout-toggler {\n        opacity: .60;\n        filter:  alpha(opacity=60);\n    }\n    .ui-layout-resizer-hover .ui-layout-toggler-hover { /* need specificity */\n        background-color: #FC6;\n        opacity: 1.00;\n        filter:  alpha(opacity=100);\n    }\n    .ui-layout-toggler-north ,\n    .ui-layout-toggler-south {\n        border-width: 0 1px; /* left/right borders */\n    }\n    .ui-layout-toggler-west ,\n    .ui-layout-toggler-east {\n        border-width: 1px 0; /* top/bottom borders */\n    }\n    /* hide the toggler-button when the pane is 'slid open' */\n    .ui-layout-resizer-sliding  ui-layout-toggler {\n        display: none;\n    }\n    /*\n     *  style the text we put INSIDE the togglers\n     */\n    .ui-layout-toggler .content {\n        color:          #666;\n        font-size:      12px;\n        font-weight:    bold;\n        width:          100%;\n        padding-bottom: 0.35ex; /* to 'vertically center' text inside text-span */\n    }\n\n.sorting_asc {\n\tbackground: url('../img/control-090-small.png') no-repeat center right;\n}\n\n.sorting_desc {\n\tbackground: url('../img/control-270-small.png') no-repeat center right;\n}\n\n.sorting {\n/*  background: url('../images/sort_both.png') no-repeat center right;*/\n}\n\n.sorting_asc_disabled {\n\tbackground: url('../img/control-090-small.png') no-repeat center right;\n}\n\n.sorting_desc_disabled {\n\tbackground: url('../img/control-270-small.png') no-repeat center right;\n}"
  },
  {
    "path": "src/js/background.js",
    "content": "/*\n * background.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n \n// oauth\nvar oauth = ChromeExOAuth.initBackgroundPage({\n  'request_url': 'https://www.google.com/accounts/OAuthGetRequestToken',\n  'authorize_url': 'https://www.google.com/accounts/OAuthAuthorizeToken',\n  'access_url': 'https://www.google.com/accounts/OAuthGetAccessToken',\n  'consumer_key': 'anonymous',\n  'consumer_secret': 'anonymous',\n  'scope': 'https://docs.google.com/feeds/',\n  'app_name': 'Scraper'\n});\n\nchrome.extension.onRequest.addListener(function(request, sender, sendResponse) {\n  var command = request.command;\n  var payload = request.payload;\n  \n  if (command === 'scraperScrapeTab') {\n    // forward requests for \"scraperScrape\" to the appropriate tab\n    chrome.tabs.sendRequest(parseInt(payload.tab, 10), { command: 'scraperScrape', payload: payload.options }, sendResponse);\n  } else if (command === 'scraperSpreadsheet') {\n    // export spreadsheet to google docs\n    oauth.authorize(function() {\n      // remove trailing colons from slug as this will result in error due to\n      // http://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=2136\n      var title = payload.title || '';\n      var slug = encodeURIComponent(title.replace(/[:]+\\s*$/,''));\n      var request = {\n        'method': 'POST',\n        'headers': {\n          'GData-Version': '3.0',\n          'Content-Type': 'text/csv',\n          'Slug': slug\n        },\n        'parameters': {\n          'alt': 'json'\n        },\n        'body': payload.csv\n      };\n      var url = 'https://docs.google.com/feeds/default/private/full';\n      \n      var callback = function(response, xhr) {\n        if (xhr.status == 401) {\n          // unauthorized, token probably bad so clear it\n          oauth.clearTokens();\n          sendResponse({error: 'Google authentication failed. Please try exporting again, and you will be re-authenticated.'});\n        } else if (xhr.status - 200 < 100) {\n          try {\n            var json = JSON.parse(response);\n        \n            // open page\n            if (json && json.entry && json.entry.link) {\n              var links = json.entry.link;\n              for (var i = 0; i < links.length; i++) {\n                if (links[i].rel === 'alternate' && links[i].type === 'text/html') {\n                  chrome.tabs.create({\n                    url: links[i].href\n                  });\n                }\n              }\n            }\n          \n            // forward response to the caller\n            sendResponse(json);\n          } catch (error) {\n            sendResponse({\n              error: error\n            });\n          }\n        } else {\n          sendResponse({\n            error: 'Received an unexpected response.\\n\\n' + response\n          });\n        }\n      };\n      \n      oauth.sendSignedRequest(url, callback, request);\n    });\n  }\n});\n\n// make some default presets\nif (!bit155.scraper.presets()) {\n  bit155.scraper.presets([\n\t  { \n\t    name: 'Paragraph Text', \n\t    options: {\n\t      language: 'xpath',\n\t      selector: '//p',\n\t      attributes: [\n\t        { xpath: '.', name: 'Text' }\n\t      ],\n\t      filters: [ 'empty' ]\n\t    }\n\t  },\n\t  { \n\t    name: 'Links', \n\t    options: {\n\t      language: 'xpath',\n\t      selector: '//a',\n\t      attributes: [\n\t        { xpath: '.', name: 'Link' },\n\t        { xpath: '@href', name: 'URL' }\n\t      ],\n\t      filters: ['empty']\n\t    }\n\t  }\n\t]);\n};\n\n// context menus\nvar scrapeSimilarItem = chrome.contextMenus.create({\n  title: \"Scrape similar...\",\n  contexts: ['all'],\n  onclick: function(info, tab) {\n    var active = false;\n\n    // get selection options and open viewer with the response\n    chrome.tabs.sendRequest(tab.id, { command: 'scraperSelectionOptions' }, function(response) {\n      active = true;\n      bit155.scraper.viewer(tab, response);\n    });\n    \n    // offer to reload page if no response\n    setTimeout(function() {\n      if (!active && confirm('You need to reload this page before you can use Scraper. Press ok if you would like to reload it now, or cancel if not.')) {\n        chrome.tabs.update(tab.id, {url: \"javascript:window.location.reload()\"});\n      }\n    }, 500);\n  }\n});\n"
  },
  {
    "path": "src/js/bit155/attr.js",
    "content": "/*\n * attr.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nvar bit155 = bit155 || {};\n\n/**\n * Creates an attribute accessor function. \n *\n * If one argument is passed to the function, then the value will be assigned\n * to the attribute.\n *\n * If multiple arguments are passed, then they will be stored in an array and\n * the array will be assigned to the attribute.\n *\n * Otherwise, if no arguments are provided, then the value of the attribute is\n * returned.\n *\n * @param initial {any} the initial value, will NOT be passed through the \n *        filter\n * @param filter {function(newValue, oldValue)} (optional) function called \n *        before assigning a new value, which returns a filtered version of \n *        the value\n * @param callback {function(newValue, oldValue)} (optional) function called \n *        after assigning a new value\n */\nbit155.attr = function(options) {\n  var _value = options ? options.initial : null;\n  var filter = options ? options.filter : false;\n  var callback = options ? options.callback : false;\n\n  return function() {\n    var newValue, oldValue;\n    \n    if (arguments.length > 0) {\n      if (arguments.length === 1) {\n        newValue = arguments[0];\n      } else {\n        var i;\n        newValue = [];\n        for (i = 0; i < arguments.length; i++) {\n          newValue.push(arguments[i]);\n        }\n      }\n      \n      // filter value\n      oldValue = _value;\n      if (filter) {\n        var filteredValue = filter.call(this, newValue, oldValue);\n        if (filteredValue !== undefined) {\n          newValue = filteredValue;\n        }\n      }\n      \n      // copy new value\n      if (typeof newValue === 'object') {\n        if ($.isArray(newValue)) {\n          _value = $.extend(true, [], newValue);\n        } else {\n          _value = $.extend(true, {}, newValue);          \n        }\n      } else {\n        _value = newValue;\n      }\n      \n      if (callback) {\n        callback.call(this, newValue, oldValue);\n      }\n      \n      return this;\n    }\n    \n    return _value;\n  };\n};\n"
  },
  {
    "path": "src/js/bit155/csv.js",
    "content": "/*\n * csv.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nvar bit155 = bit155 || {};\nbit155.csv = bit155.csv || {};\n\n/**\n * Encodes a CSV cell.\n * @param cell {string} cell to encode\n */\nbit155.csv.cell = function(cell) {\n  var str;\n  \n  if (cell === undefined || cell === null) {\n    return \"\";\n  } else if (typeof cell === 'string') {\n    str = cell;\n  } else {\n    str = cell.toString();\n  }\n  \n  if (str.match(/[,\"\\n\\r]/)) {\n    str = str.replace(/([\"])/g, '\"$1');\n    str = '\"' + str + '\"';\n  }  \n  return str;\n};\n\n/**\n * Encodes an array as a CSV row. Accepts an array of values or you can pass\n * variable arguments to it.\n *\n * @param row (any) a single array of values or any number of variable \n *        arguments\n */\nbit155.csv.row = function() {\n  var row, text = '', i;\n  \n  if (arguments.length === 1) {\n    row = $.isArray(arguments[0]) ? arguments[0] : arguments;\n  } else {\n    row = arguments;\n  }\n  \n  for (i = 0; i < row.length; i++) {\n    if (i > 0) {\n      text += ',';\n    }\n    text += bit155.csv.cell(row[i]);\n  }\n  return text;\n};\n\nbit155.csv.csv = function(data) {\n  var text = '';\n  var i;\n  \n  if (!$.isArray(data)) {\n    return \"\";\n  }\n  \n  for (i = 0; i < data.length; i++) {\n    text += bit155.csv.row(data[i]) + '\\n';\n  }\n  \n  return text;\n};"
  },
  {
    "path": "src/js/bit155/scraper.js",
    "content": "/*\n * scraper.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nvar bit155 = bit155 || {};\nbit155.scraper = bit155.scraper || {};\n\n/**\n * Function that creates a new viewer window bound to the specified tab.\n *\n * @param {Object} tab (optional) the tab object to bind the viewer to \n *        (defaults to the currently selected tab)\n * @param {Object} options (optional) options to initialize viewer with\n */\nbit155.scraper.viewer = function(tab, options) {\n  options = options || {};\n  \n  // call this again with selected tab if none specified\n  if (!tab) {\n    chrome.tabs.getSelected(undefined, function(tab) {\n      if (tab) {\n        bit155.scraper.viewer(tab, options);\n      }\n    });\n    return;\n  }\n\n  // can't work on extensions pages\n  if (tab.url.indexOf(\"https://chrome.google.com/extensions\") == 0 || tab.url.indexOf(\"chrome://\") == 0) {\n    alert(\"Scraper is not permitted to work on the Google Chrome extensions page for security reasons.\");\n    return;\n  }\n  \n  // open window if we get a ping response\n  chrome.windows.create({ \n    url: chrome.extension.getURL('viewer.html') \n      + \"?tab=\" + tab.id\n      + \"&options=\" + encodeURIComponent(JSON.stringify(options)),\n    type: 'popup',\n    width: Math.max(650, parseInt((localStorage['viewer.width'] || '960'), 10)),\n    height: Math.max(250, parseInt((localStorage['viewer.height'] || '400'), 10))\n  });\n};\n\n/**\n * Contains presets, backed by localStorage['presets']. Contains migration\n * from the old localStorage['viewer.presets'] since this attribute has \n * larger scope than just the viewer.\n */\nbit155.scraper.presets = bit155.attr({\n  initial: JSON.parse(localStorage['presets'] || localStorage['viewer.presets'] || 'null'),\n  filter: function(v) {\n    if (v && !$.isArray(v)) {\n      throw new Error('Preset must be an array.');\n    }\n    return v;\n  },\n  callback: function(v) {\n    localStorage['presets'] = v ? JSON.stringify(v) : null;\n  }\n});\n\n/**\n * Generates an xpath that is specific, but hopefully not too specific, for\n * a node.\n *\n * @param {Object} node to generate xpath for\n */\nbit155.scraper.xpathForNode = function(node) {\n  var xpath = $(node).xpath(),\n      xpathLastPredicateRegex = /^(.*)(\\[\\d+\\])([^\\[\\]]*)$/,\n      xpathFirstSegmentRegex = /^(\\/+[^\\/]+)(.*)$/,\n      result,\n      selection,\n      selectionTrimmed;\n  \n  // keep cutting out the last predicate until we match more than one node\n  // and consider this our ideal selection\n  while ((result = xpathLastPredicateRegex.exec(xpath))) {\n    selection = bit155.scraper.select(document, xpath, 'xpath');\n    if (selection.length > 1) {\n      break;\n    }\n    xpath = result[1] + result[3];\n  }\n  \n  if (!selection) {\n    return xpath;\n  }\n  \n  // trim the front of the path until we have smallest xpath that returns\n  // same number of elements\n  while ((result = xpathFirstSegmentRegex.exec(xpath))) {\n    selectionTrimmed = bit155.scraper.select(document, '/' + result[2], 'xpath') || [];\n    if (selectionTrimmed.length !== selection.length) {\n      break;\n    }\n    xpath = '/' + result[2];\n  }\n  \n  return xpath;\n};\n\n/**\n * Generates bit155.scraper.scrape options for the given selection. Uses magic\n * to try and guess reasonable defaults.\n *\n * @param {Object} focusNode same semantics as Selection.focusNode\n * @param {Object} anchorNode (optional) same as Selection.anchorNode\n * @param {HTMLDocument} doc the document in which to match\n */\nbit155.scraper.optionsForSelection = function(focusNode, anchorNode, doc) {\n  var options = {}, \n      ancestor, \n      ancestorTagName, \n      ancestorClassName, \n      node;\n\n  doc = doc || window.document;\n  \n  // determine common ancestor based on user's current selection\n  if (anchorNode) {\n    ancestor = $([focusNode, anchorNode]).commonAncestor();\n  } else {\n    ancestor = $(focusNode).closest('*');\n  }\n  \n  // tweak ancestor for some types of elements\n  // XXX design\n  if (ancestor && ancestor.length > 0) {\n    ancestorTagName = ancestor.get(0).tagName.toLowerCase();\n    if (ancestorTagName === 'table' || ancestorTagName === 'tbody' || ancestorTagName === 'thead' || ancestorTagName === 'tfoot') {\n      // table? select rows instead\n      ancestor = $(focusNode).closest('tr');\n    } else if (ancestorTagName === 'dl') {\n      // dl? select terms instead\n      ancestor = ancestor.find('dt').first();\n    } else if (ancestorTagName === 'ul' || ancestorTagName === 'ol') {\n      // dl? select terms instead\n      ancestor = ancestor.find('li').first();\n    }\n  }\n  \n  // populate options\n  options.language = 'jquery';\n  options.selector = '';\n  options.attributes = [];\n  if (ancestor && ancestor.length > 0) {\n    node = ancestor.get(0);\n    ancestorTagName = node.tagName.toLowerCase();\n    ancestorClassName = $.trim(node.className);\n    options.selector = ancestorTagName;\n    \n    // find first xpath that matches more than one element by removing the\n    // index selector from each xpath segment. biggest caveats:\n    //\n    //  * only selecting elements with same structure\n    //  * won't work when selecting an outlier with deeper structure than peers\n    //  * ignores semantics\n    //\n    options.language = 'xpath';\n    options.selector = bit155.scraper.xpathForNode(node);\n    \n    // use \"magical\" attributes depending on what custom ancestor is\n    if (ancestorTagName === 'tr') {\n      var headers = (function() {\n        var table = ancestor.closest('table');\n        var columns = ancestor.children().length;\n        var firstRow = table.find('tr').first();\n        var headerRow;\n                \n        // find first row in the table, and if it contains the same number of\n        // TH cells as data cells in our TR ancestor, then assume it contains\n        // column names\n        if (firstRow && firstRow.children('th').length == columns) {\n          headerRow = firstRow;\n        } else {\n          headerRow = ancestor;\n        }\n        \n        return headerRow.children().map(function(index, cell) {\n          if (cell.tagName === 'TH') {\n            return $(cell).text();\n          } else {\n            return 'Column ' + (index + 1);\n          }\n        });\n      })();\n      \n      // create an attribute for each header\n      $.each(headers, function(index,name) {\n        options.attributes.push({ xpath: '*[' + (index + 1) + ']', name: name });\n      });\n      \n      // append a [td] constraint to the selector so that we don't scrape\n      // rows containing only headers\n      options.selector = options.selector + \"[td]\";\n    } else if (ancestorTagName === 'a') {\n      options.attributes.push({ xpath: '.', name: 'Link' });\n      options.attributes.push({ xpath: '@href', name: 'URL' });\n    } else if (ancestorTagName === 'img') {\n      options.attributes.push({ xpath: '@title', name: 'Title' });\n      options.attributes.push({ xpath: '@src', name: 'Source' });\n    } else if (ancestorTagName === 'dt') {\n      options.attributes.push({ xpath: '.', name: 'Term' });\n      options.attributes.push({ xpath: './following-sibling::dd', name: 'Definition' });\n    } else {\n      options.attributes.push({ xpath: '.', name: 'Text' });\n    }\n  }\n  \n  return options;\n};\n\n/**\n * Selects elements using a selector string in some language.\n *\n * @param {node} context what to search\n * @param {string} selector the query string\n * @param {string} language what language (\"jquery\" or \"xpath\") the selector \n *        is expressed in\n */\nbit155.scraper.select = function(context, selector, language) {\n  if (typeof context !== 'object') {\n    throw \"Context object is required.\";\n  }\n  if (typeof selector !== 'string') {\n    throw \"Selector string is required.\";\n  }\n  \n  if (language === 'xpath') {\n    // https://developer.mozilla.org/en/XPathResult\n    // http://stackoverflow.com/questions/727902/jquery-select-text\n    var xpr = document.evaluate(selector, context || document, null, XPathResult.ANY_TYPE, null);\n    var i, item, result = [];\n    for (i = 0; item = xpr.iterateNext(); i++) {\n      result.push(item);\n    }\n    \n    return $(result);\n  } else if (language === 'jquery') {\n    return $(context).find(selector);\n  } else {\n    throw new Error('Unsupported selector language: ' + language);\n  }\n};\n\n/**\n * Scrapes a page.\n */\nbit155.scraper.scrape = function(options) {\n  var selector = options['selector'];\n  var attributes = options['attributes'] || [];\n  var filters = options.filters || [];\n  var result = [];\n  \n  // make sure xpath in each attribute\n  $.each(attributes, function() {\n    if (!this.xpath) {\n      throw new Error(\"XPath is required for each attribute.\");\n    }\n  });\n  \n  // collect results\n  bit155.scraper.select(document, options.selector, options.language).each(function(i,e) {\n    var el = $(e);\n    var values = [];\n    var include = true;\n    \n    if (attributes) {\n      var xpathResult = null;\n      \n      $.each(attributes, function() {\n        values.push(document.evaluate(this.xpath, e, null, XPathResult.STRING_TYPE, null).stringValue);\n      });\n    }\n    \n    result.push({\n      'xpath': el.xpath(),\n      'values': values\n    });\n  });\n  \n  // apply filters\n  $.each(filters, function(i,filter) {\n    if (filter === 'empty') {\n      result = result.filter(function(result) {\n        for (var i = 0; i < result.values.length; i++) {\n          if ($.trim(result.values[i]) !== '') {\n            return true;\n          }\n        }\n        return false;\n      });\n    }\n  });\n  \n  return result;\n};"
  },
  {
    "path": "src/js/contentscript.js",
    "content": "/*\n * contentscript.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright \n * notice, this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *  \n *     * Neither the name of bit155 nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n(function(){\n  // listen for context menu\n  var contextNode;\n  addEventListener(\"contextmenu\", function(e) {\n    contextNode = e.srcElement;\n  });\n  \n  // listen for requests\n  chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {\n    var command = request.command,\n        payload = request.payload,\n        response = $.extend({}, payload);\n\n    try {\n      if (command === 'scraperScrape') {\n        // scrape\n        response.result = bit155.scraper.scrape(response);\n      } else if (command === 'scraperSelectionOptions') {\n        // selection options\n        (function(){\n          var focusNode,\n              anchorNode, \n              selectionDocument,\n              selection;\n              \n          // abort if no contextNode as probably being invoked from another\n          // frame\n          if (!contextNode) {\n            response.error = \"Frames are not supported at the moment. Please open the frame in a new tab or window and try scraping again.\";\n            return;\n          }\n          \n          // determine range of selection\n          selection = window.getSelection();\n          selectionDocument = window.document;\n          if (selection.isCollapsed) {\n            // nothing selected, so use whatever node is under the cursor\n            focusNode = contextNode;\n          } else {\n            // select focus and anchor nodes from selection\n            focusNode = selection.focusNode;\n            anchorNode = selection.anchorNode;\n          }\n          \n          // clear context node\n          contextNode = null;\n          \n          // extend response with options generated from current selection\n          response = $.extend(response, bit155.scraper.optionsForSelection(focusNode, anchorNode, selectionDocument));\n        }());\n      } else if (command === 'scraperHighlight') {\n        // highlight\n        (function() {\n          var elements;\n\n          if (payload.selector) {\n            elements = bit155.scraper.select(document, payload.selector, payload.language);\n          } else if (payload.xpath) {\n            elements = bit155.scraper.select(document, payload.xpath, 'xpath');\n          } else if (payload.jquery) {\n            elements = $(payload.jquery);\n          }\n\n          if (elements) {\n            window.scrollTo(elements.offset().left, elements.offset().top);\n            elements.filter(':visible').effect('highlight', {}, 'slow');\n          }          \n        }());\n      } else if (command === 'scraperPing') {\n        // ping\n      } else {\n        throw new Error('Unsupported request: ' + JSON.stringify(request));\n      }\n    } catch (error) {\n      console.error(error);\n      response.error = error;\n    }\n\n    sendResponse(response);\n  });  \n}());\n"
  },
  {
    "path": "src/js/popup.js",
    "content": "/*\n * popup.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *   * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *  \n *   * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the \n * documentation and/or other materials provided with the distribution.\n *  \n *   * Neither the name of bit155 nor the names of its contributors may be\n * used to endorse or promote products derived from this software without\n * specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n$(function() {\n  var \n    presets = bit155.scraper.presets(),\n    presetList = $('#presets');\n\n  $('.viewer').click(function() {\n    bit155.scraper.viewer();\n    return false;\n  });\n  \n  if (presets.length === 0) {\n    presetList.append($('<li class=\"disabled\">').text(\"No presets have been defined yet.\"));\n  } else {\n    $.each(presets, function(index, preset) {\n      presetList.append($('<li class=\"preset\">').append($('<a href=\"javascript:;\">').text(preset.name).click(function() {\n        bit155.scraper.viewer(null, preset.options);\n        return false;\n      })));\n    });\n  }\n});"
  },
  {
    "path": "src/js/shared.js",
    "content": "/*\n * shared.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// $(...).serializeParams()\n// --------------------------------------------------------------------------\n\n/**\n * Plugin that generates an object containing parameters of a form. Allows\n * Railsesque multi-dimensional parameter names (eg. 'user[name]' and \n * 'users[][name]').\n */\n(function($){\n  /**\n   * Splits a parameter name into an array of tokens. Empty brackets are \n   * tokenized as `undefined` and indicate that the preceding token should be\n   * considered an array.\n   */\n  function _parseParam(str) {\n    var path = [];\n    var s = str;\n\n    // first match expects no brackets, subsequent matches do\n    for (var match = s.match(/^([^\\[]*)(.*)$/); match; match = s.match(/^\\[([^\\]]*)\\](.*)$/)) {\n      path.push(match[1] || undefined);\n      s = match[2];\n    }\n    \n    // if there is a remaining string, then it was probably malformed, so warn\n    // user and return a single-segment path consisting of just str (so that\n    // code doesn't break)\n    if (s) {\n      if (console && console.warn) { \n        console.warn('Malformed path: ' + str); \n      }\n      return [str];\n    }\n    \n    return path;\n  }\n  \n  $.fn.serializeParams = function() {\n    var result = {};\n\n    $.each($(this).serializeArray(), function() {\n      var keys = _parseParam(this.name);\n      var containers = [result];\n      \n      for (var i = 0; i < keys.length; i++) {\n        var container = containers[containers.length - 1];\n\n        var key = keys[i];\n        var keyIndicatesArray = keys[i+1] === undefined;\n        \n        var leaf = (i === keys.length - 1);\n        \n        // handle four cases:\n        if (leaf && key === undefined) {\n          // LEAF ARRAY\n          container.push(this.value);\n        } else if (leaf) {\n          // LEAF OBJECT\n          // if nothing already defined here, assign value, otherwise we need\n          // to convert existing value into an array and append or find an\n          if (container[key] === undefined) {\n            container[key] = this.value;\n          } else {\n            // collision! create an array here or add new element to an \n            // ancestor array\n            var lastUndefinedKey = keys.lastIndexOf(undefined);\n            \n            if (lastUndefinedKey < 0) {\n              container[key] = [container[key], this.value];\n            } else {\n              for (; i >= 0; i--) {\n                if (keys[i] === undefined) {\n                  break;\n                }\n                containers.pop();\n              }\n              \n              containers[containers.length - 1].push({});\n              i = i - 1;\n              continue;\n            }\n          }\n        } else if (key === undefined) {\n          // INNER ARRAY\n          if (container.length === 0) {\n            container.push({});\n          }\n          containers.push(container[container.length - 1]);\n        } else {\n          // INNER NODE\n          if (container[key] === undefined) {\n            container[key] = (keyIndicatesArray) ? [] : {};\n          }\n          containers.push(container[key]);\n        }\n      }\n    });\n    \n    return result;\n  };\n}(jQuery));\n\n// $(...).xpath\n// --------------------------------------------------------------------------\n\n/**\n * Returns the xpath of an element.\n */\n(function($){\n  $.fn.xpath = function(options) {\n    var node;\n    var path = \"\";\n    var tag, segment, siblings;\n    \n    for (node = this.get(0); node && node.nodeType == 1; node = node.parentNode) {\n      tag = node.tagName.toLowerCase();\n      segment = tag;\n      \n      // append index\n      siblings = $(node).parent().children(tag);\n      if (siblings.length > 1) {\n        path = \"/\" + tag + \"[\" + (siblings.index(node) + 1) + \"]\" + path;\n      } else {\n        path = \"/\" + tag + path;\n      }\n    }\n    \n    return path;\t\n  };\n}(jQuery));\n\n// $(...).cssSelector\n// --------------------------------------------------------------------------\n\n/**\n * The CSS selector plugin lets you generate CSS selectors of elements.\n */\n(function($){\n  var component = function(el, options) {\n    var str = '';\n\n    if (options.tagName && el.tagName) str = str + el.tagName;\n    if (options.id && el.id) str = str + '#' + el.id;\n    if (options.classes && el.className) str = str + '.' + el.className.split(/\\s+/).join('.');\n    if (options.attributes && el.attributes) {\n      $.each(el.attributes, function(i, attr) {\n        str = str + '[' + attr.name + \"='\" + attr.value + \"']\";\n      });\n    }\n\n    return str;  \n  };\n  \n  var path = function(el, options) {\n    var path = [];\n    \n    path.push(component(el, options));\n    el.parents().each(function(i,el) { \n      path.push(component(this, options));\n    }).get();\n    \n    return path.reverse();\n  };\n    \n  $.fn.cssSelector = function(options) {\n    var settings = {\n      tagName: true, \n      id: true, \n      classes: true, \n      attributes: false\n    };\n    \n    if (options) {\n      $.extend(settings, options);\n    }\n\n    return path(this, settings).filter(function(e,i,a) { return e; }).join(' > ');\n  };\n}(jQuery));\n\n// $(...).commonAncestor\n// --------------------------------------------------------------------------\n\n(function($) {\n  $.fn.commonAncestor = function() {\n    // http://stackoverflow.com/questions/3217147/jquery-first-parent-containing-all-children\n    var parents = [];\n    var minlen = Infinity;\n    var i;\n\n    $(this).each(function() {\n      var curparents = $(this).parents();\n      parents.push(curparents);\n      minlen = Math.min(minlen, curparents.length);\n    });\n\n    for (i in parents) {\n      parents[i] = parents[i].slice(parents[i].length - minlen);\n    }\n\n    // Iterate until equality is found\n    for (i in parents[0]) {\n      var equal = true;\n      for (var j in parents) {\n        if (parents[j][i] != parents[0][i]) {\n          equal = false;\n          break;\n        }\n      }\n      if (equal) {\n        return $(parents[0][i]);\n      }\n    }\n    return $([]);\n  };\n}(jQuery));\n\n"
  },
  {
    "path": "src/js/viewer.js",
    "content": "/*\n * viewer.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * Sort of a controller class for the viewer and work-in-progress towards a\n * real architecture. Mostly so I can test some of the logic in it.\n */\nvar Viewer = function() {};\n\n/**\n * Contains the scrape data.\n */\nViewer.prototype.data = bit155.attr({\n  callback: function(v) { \n    this.reload(); \n  }\n});\n\n/**\n * Contains the id of the tab this is connected to.\n */\nViewer.prototype.tabId = bit155.attr({\n  filter: function(v) { \n    return parseInt(v, 10);\n  }\n});\n\n/**\n * Reloads data of elements dependent on bit155.scraper.presets data.\n */\nViewer.prototype.reloadPresets = function() {\n  var list;\n  var self = this;\n  var presets = bit155.scraper.presets();\n  \n  // update list\n  list = $('#presets-list');\n  list.empty();\n  $.each(presets || [], function(i, preset) {\n    var handle = $('<img class=\"preset-handle\" src=\"img/application-form.png\">');\n    var load = $('<a class=\"preset-load\" href=\"javascript:;\" title=\"Load this preset.\">').text(preset.name).click(function() {\n      self.options(preset.options);\n      $('#presets-form-name').val(preset.name);\n      $('#presets').dialog('close');\n      self.scrape();\n      return false;\n    });\n    var remove = $('<a class=\"preset-remove\" href=\"javascript:;\" title=\"Remove this preset.\">').append($('<img src=\"img/bullet_delete.png\" title=\"Remove preset.\">')).click(function() {\n      if (confirm('Are you sure you want to remove the preset, \"' + preset.name + '\"?')) {\n        presets.splice(i,1);\n        bit155.scraper.presets(presets);\n        self.reloadPresets();\n      }\n    });\n    \n    list.append($('<li>').attr('id', 'preset-' + i).append(handle).append(remove).append(load));\n  });\n};\n\n/**\n * Returns the current options (as encapsulated by the form) or sets new \n * options.\n *\n * @param opts {object} (optional) new options to set\n */\nViewer.prototype.options = function(opts) {\n  if (opts) {\n    var self = this;\n    \n    // selector and language\n    $('#options-selector').val(opts.selector).change();\n    $('#options-language').val(opts.language).change();\n    \n    // attributes\n    if ($.isArray(opts.attributes) && opts.attributes.length > 0) {\n      $('#options-attributes tbody').empty();\n      $.each(opts.attributes, function() {\n        self.addAttribute(this.xpath, this.name);\n      });\n    } else {\n      self.addAttribute('.', 'Text');\n    }\n    \n    // filters\n    $('#options-filters').find('input:checkbox').attr('checked', false);\n    if ($.isArray(opts.filters) && opts.filters.length > 0) {\n      $.each(opts.filters, function(index, filter) {\n        if (filter === 'empty') {\n          $('#options-filters-empty').attr('checked', true);\n        }\n      });\n    }\n    \n    return this;\n  } else {\n    return $('#options').serializeParams();\n  }\n};\n\n/**\n * Adds an attribute to the options.\n *\n * @param xpath {string}\n * @param name {string}\n * @param context {element} another row to add attribute beneath, or null if\n *        it should be appended to the end of the table\n */\nViewer.prototype.addAttribute = function(xpath, name, context) {\n  var self = this;\n  var xpathInput = $('<input>').attr('type', 'text').attr('name', 'attributes[][xpath]').attr('placeholder', 'XPath').val(xpath || '');\n  var nameInput = $('<input>').attr('type', 'text').attr('name', 'attributes[][name]').attr('placeholder', 'Name (optional)').val(name || '');\n  var row = $('<tr>');\n  \n  var addRow = function() {\n    self.addAttribute('', '', row);\n    return false;\n  };\n  var deleteRow = function() {\n    var parent = row.parent();\n    if (parent.children().length > 1) {\n      row.fadeOut('fast', function() { row.remove(); });\n    } else {\n      xpathInput.val('');\n      nameInput.val('');\n    }\n    return false;\n  };\n\n  // create row\n  row.append($('<td nowrap>').addClass('dragHandle').text(' '));\n  row.append($('<td>').append(xpathInput));\n  row.append($('<td>').append(nameInput));\n  row.append($('<td nowrap>')\n    .append($('<a>').attr('href', 'javascript:;').click(deleteRow).html('<img src=\"img/bullet_delete.png\">'))\n    .append($('<a>').attr('href', 'javascript:;').click(addRow).html('<img src=\"img/bullet_add.png\">'))\n  );\n  row.hide();\n  \n  // insert row\n  var after = function() {\n    $('#options-attributes').tableDnD({\n      dragHandle: 'dragHandle'\n    });\n  };\n  \n  if (context) {\n    context.after(row.fadeIn('fast', after));\n  } else {\n    $('#options-attributes tbody').append(row.fadeIn('fast', after));\n  }\n};\n\n/**\n * Displays an error message.\n *\n * @param {Object} an error object containing a \"message\" property, or a\n *        string, to display\n */\nViewer.prototype.error = function(error) {\n  $('<div class=\"error\">').text(error.message ? error.message : '' + error).dialog({\n    title: 'Error',\n    modal: true,\n    buttons: [{\n      text: \"Close\",\n      click: function() { $(this).dialog(\"close\"); }\n    }]\n  });\n};\n\n/**\n * Reloads the view based on current data.\n */\nViewer.prototype.reload = function() {\n  var self = this;\n  var data = this.data();\n  var results = data.result || [];\n  var attributes = data.attributes || [];\n\n  // headers\n  var thead = $('<thead>');\n  var headerRow = $('<tr>').appendTo(thead).append('<th>&nbsp;</th>').append('<th>&nbsp;</th>');\n  $.each(attributes, function() {\n    headerRow.append($('<th>').text(this.name));\n  });\n\n  // body\n  var tbody = $('<tbody>');\n  $.each(results, function(i,result) {\n    var row = $('<tr>').appendTo(tbody);\n    var tools = $('<td class=\"tools\" nowrap>').appendTo(row);\n\n    // tools\n    tools.append($('<img src=\"img/highlighter-small.png\" title=\"Highlight in document.\">').click(function() {\n      chrome.tabs.sendRequest(self.tabId(), { command: 'scraperHighlight', payload: { xpath: result.xpath } });\n    }));\n    \n    // index\n    row.append($('<td class=\"index\" nowrap>').text(i + 1));\n    \n    // attributes\n    $.each(attributes, function(j,attribute) {\n      var value = result.values[j];\n      var cell = $('<td>').text(value);\n      \n      row.append(cell);\n    });\n  });\n\n  var url = /^https?:\\/\\/[^\\s]+$/i;\n  var table = $('<table>').append(thead).append(tbody).appendTo($('#results-table').empty());\n  table.dataTable({\n    'bInfo': false,\n    'bFilter': false,\n    'bStateSave': true,\n    'bPaginate': false,\n    'fnRowCallback': function(row, values, displayIndex, displayIndexFull) {\n      $('td', row).each(function() {\n        var text = $(this).text();\n        if (url.test(text)) {\n          $(this).empty().append($('<a>').attr('href', text).attr('target', '_blank').text(text));\n        }\n      });\n      \n      return row;\n    },\n    'aoColumnDefs': [\n      { \n        aTargets: [0],\n        bSortable: false\n      }\n    ]\n  });\n};\n\n/**\n * Scrapes the host document using the current options.\n */\nViewer.prototype.scrape = function() {\n  var self = this;\n  var options = self.options();\n  \n  // clean out empty attributes and set names for empties\n  options.attributes = $.map(options.attributes.filter(function(a) { return a.xpath !== ''; }), function(a) {\n    if (!a.name) {\n      a.name = a.xpath;\n    }\n    return a;\n  });\n  \n  var request = { \n    command: 'scraperScrapeTab', \n    payload: {\n      tab: self.tabId(),\n      options: options\n    }\n  };\n  \n  chrome.extension.sendRequest(request, function(response) { \n    if (response.error) {\n      self.error(response.error);\n    }\n    self.data(response); \n  });\n};\n\n/**\n * Creates a Google spreadsheet with the current data.\n */\nViewer.prototype.spreadsheet = function() {\n  var self = this;\n  var data = [];\n  var csv;\n  \n  // gather up data and convert to csv\n  data.push($.map(this.data().attributes || [], function(a) { return a.name || a.xpath; }));\n  $.each(this.data().result || [], function(index, result) {\n    data.push(result.values);\n  });\n  csv = bit155.csv.csv(data);\n\n  // find the host tab so we can get its title\n  chrome.tabs.get(self.tabId(), function(tab) {\n    var request = {};\n    var dialog = $('<div>').addClass('progress');\n    var title = tab.title;\n    \n    // ask user for title\n    // title = prompt('Please enter a title for your Google spreadsheet:', title);\n    //     if (!title) {\n    //       return;\n    //     }\n    \n    // tell user to wait\n    dialog.append($('<div style=\"margin: 30px; text-align: center\"><img src=\"img/progress.gif\"></div>'));\n    dialog.dialog({\n      closeOnEscape: true,\n      buttons: [],\n      resizable: false,\n      title: 'Exporting to Google Docs...',\n      modal: true\n    });\n    \n    // send spreadsheet request to background.js\n    request.command = 'scraperSpreadsheet';\n    request.payload = {\n      title: title,\n      csv: csv\n    };\n    chrome.extension.sendRequest(request, function(response) {\n      dialog.dialog('close');\n      if (response.error) {\n        self.error(response.error);\n      }\n    });\n  });\n};\n\n// from http://safalra.com/web-design/javascript/parsing-query-strings/\nfunction parseQueryString(_1){var _2={};if(_1==undefined){_1=location.search?location.search:\"\";}if(_1.charAt(0)==\"?\"){_1=_1.substring(1);}_1=_1.replace(/\\+/g,\" \");var _3=_1.split(/[&;]/g);for(var i=0;i<_3.length;i++){var _5=_3[i].split(\"=\");var _6=decodeURIComponent(_5[0]);var _7=decodeURIComponent(_5[1]);if(!_2[_6]){_2[_6]=[];}_2[_6].push((_5.length==1)?\"\":_7);}return _2;}\n\n$(function() {\n  var response = parseQueryString(),\n      responseOptions = response.options && response.options.length > 0 ? JSON.parse(response.options[0]) : {},\n      savedOptions = JSON.parse(localStorage['viewer.options'] || JSON.stringify({\n          selector: 'a',\n          language: 'jquery',\n          attributes: [\n            { xpath: '.', name: 'Link' },\n            { xpath: '@href', name: 'URL' }\n          ],\n          filters: [\n            'empty'\n          ]\n        })),\n      options = $.extend({}, savedOptions, responseOptions);\n  \n  // create viewer\n  var viewer = new Viewer();\n  viewer.tabId(response.tab && response.tab.length > 0 ? parseInt(response.tab[0], 10) : -1);\n  viewer.options(options);\n  \n  // layout view\n  var layout = $('body').layout({ \n    west: {\n      size: 340,\n      minSize: 250,\n      closable: true,\n      resizable: true,\n      slidable: true\n    }\n  });\n  if (localStorage['viewer.west.size']) {\n    layout.sizePane('west', localStorage['viewer.west.size']);\n  }\n  if (localStorage['viewer.west.closed'] == 'true') {\n    layout.close('west');\n  }\n  $('#bottom').accordion({\n    collapsible: true,\n    active: false,\n    autoHeight: false,\n    animated: false\n  });\n  $('#center').tabs();\n  \n  // bind buttons to viewer\n  $('#options').submit(function() { viewer.scrape(); return false; });\n  $('#export').submit(function() { viewer.spreadsheet(); return false; });\n  \n  // close the window when the tab is closed\n  chrome.tabs.onRemoved.addListener(function(tabId) {\n    if (tabId == viewer.tabId()) {\n      window.close();\n    }\n  });\n  \n  // update title whenever tab changes\n  var updateMeta = function(tab) {\n    document.title = \"Scraper - \" + tab.title;\n\n    $('#options-meta-page').empty().append($('<a>').attr('href', tab.url).text(tab.title).click(function() {\n      chrome.tabs.update(viewer.tabId(), { selected: true });\n      return false;\n    }));\n    \n    // resize content since the header height may change and this buggers up\n    // the footer\n    layout.resizeContent('west');\n  };\n  chrome.tabs.get(viewer.tabId(), updateMeta);\n  chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {\n    if (tabId === viewer.tabId()) {\n      updateMeta(tab);\n    }\n  });\n  \n  // help dialog\n  $('#about').dialog({\n    autoOpen: false,\n    draggable: false,\n    resizable: false,\n    title: 'About',\n    width: 400,\n    show: 'fade',\n    hide: 'fade',\n    modal: true,\n    closeText: 'Close',\n    buttons: [{\n      text: \"Close\",\n      click: function() { $(this).dialog(\"close\"); }\n    }]\n  });\n  $('#about-link').click(function() {\n    $('#about').dialog('open');\n    return false;\n  });\n  \n  // presets\n  $('#presets').dialog({\n    autoOpen: false,\n    width: Math.max(100, parseInt(JSON.parse(localStorage['viewer.presets.width'] || '400'), 10)),\n    height: Math.max(100, parseInt(JSON.parse(localStorage['viewer.presets.height'] || '300'), 10)),\n    position: JSON.parse(localStorage['viewer.presets.position'] || '\"center\"'),\n    modal: true,\n    title: 'Presets',\n    beforeClose: function() {\n      var position = $(this).dialog('option', 'position');\n      \n      localStorage['viewer.presets.position'] = JSON.stringify([position[0], position[1]]);\n      localStorage['viewer.presets.width'] = $(this).dialog('option', 'width');\n      localStorage['viewer.presets.height'] = $(this).dialog('option', 'height');\n    }\n  });\n  $('#options-presets-button').click(function() {\n    $('#presets').dialog('open');\n    return false;\n  });\n  $('#presets-form').submit(function() {\n    var preset = {};\n    var presetList = bit155.scraper.presets();\n    var presetForm = $(this).serializeParams();\n    var options = viewer.options();\n    var i;\n    \n    // make sure it's a unique name\n    if ($.trim(presetForm.name || '') === '') {\n      viewer.error('You must specify a name for the preset.');\n      return false;\n    }\n    \n    for (i = 0; i < presetList.length; i++) {\n      if (presetList[i].name === presetForm.name) {\n        if (!confirm('There is already a preset with the name \"' + presetForm.name + '\". Do you want to overwrite the existing preset?')) {\n          return false;\n        }\n      }\n    }\n    \n    // configure preset\n    preset.name = presetForm.name;\n    preset.options = {};\n    preset.options.language = options.language;\n    preset.options.selector = options.selector;\n    preset.options.attributes = $.extend(true, [], options.attributes);\n    preset.options.filters = $.extend(true, [], options.filters);\n    \n    // remove existing presets with the same name, append new preset, and save\n    presetList = presetList.filter(function(p) { return p.name !== preset.name; });\n    presetList.unshift(preset);\n    bit155.scraper.presets(presetList);\n    viewer.reloadPresets();\n    \n    return false;\n  });\n  $('#presets-list').sortable({\n    update: function(event, ui) {\n      var presetMap = {};\n      var presetList = [];\n      \n      // map existing presets to identifier strings\n      $.each(bit155.scraper.presets(), function(i, p) {\n        presetMap['preset-' + i] = p;\n      });\n      \n      // reorder the preset list\n      $.each($(this).sortable('toArray'), function(i, id) {\n        presetList.push(presetMap[id]);\n      });\n      \n      bit155.scraper.presets(presetList);\n      viewer.reloadPresets();\n    }\n  });\n  viewer.reloadPresets();\n  \n  // reset button\n  $('#options-reset-button').click(function() {\n    if (confirm(\"Do you want to reset the options to their original values?\")) {\n      $('#presets-form-name').val('');\n      viewer.options(options);\n      viewer.scrape();\n    }\n    return false;\n  });\n  \n  // language\n  $('#options-language').change(function() {\n    var lang = $('#options-language').val();\n    $('#options-language-help').empty();\n    if (lang === 'jquery') {\n      $('#options-language-help').append($('<a href=\"http://api.jquery.com/category/selectors/\" target=\"_blank\">').text('jQuery Reference'));\n    } else if (lang === 'xpath') {\n      $('#options-language-help').append($('<a href=\"http://www.stylusstudio.com/docs/v62/d_xpath15.html\" target=\"_blank\">').text('XPath Reference'));\n    }\n  });\n  $('#options-language').change();\n  \n  // initial scrape\n  viewer.scrape();\n  \n  // save dimensions upon resize\n  addEventListener('resize', function(event) {\n    localStorage['viewer.width'] = window.outerWidth;\n    localStorage['viewer.height'] = window.outerHeight;\n  });\n  \n  // save options on close\n  addEventListener(\"unload\", function(event) {\n    var options = viewer.options();\n    if (!options.filters) {\n      options.filters = [];\n    }\n    localStorage['viewer.options'] = JSON.stringify(options);\n    localStorage['viewer.west.size'] = layout.state.west.size;\n    localStorage['viewer.west.closed'] = layout.state.west.isClosed;\n  }, true);\n  \n  // give selectorinput focus\n  $('#options-selector').select().focus();\n  \n  setTimeout(function() {\n    layout.resizeAll();\n  }, 100);\n  \n  // if error, wait a moment to show it\n  if (options.error) {\n    setTimeout(function() {\n      viewer.error(options.error);\n    }, 500);\n  }\n});\n\n"
  },
  {
    "path": "src/lib/datatables-1.7.4/js/jquery.dataTables.js",
    "content": "/*\n * File:        jquery.dataTables.js\n * Version:     1.7.4\n * Description: Paginate, search and sort HTML tables\n * Author:      Allan Jardine (www.sprymedia.co.uk)\n * Created:     28/3/2008\n * Language:    Javascript\n * License:     GPL v2 or BSD 3 point style\n * Project:     Mtaala\n * Contact:     allan.jardine@sprymedia.co.uk\n * \n * Copyright 2008-2010 Allan Jardine, all rights reserved.\n *\n * This source file is free software, under either the GPL v2 license or a\n * BSD style license, as supplied with this software.\n * \n * This source file is distributed in the hope that it will be useful, but \n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n * \n * For details please refer to: http://www.datatables.net\n */\n\n/*\n * When considering jsLint, we need to allow eval() as it it is used for reading cookies and \n * building the dynamic multi-column sort functions.\n */\n/*jslint evil: true, undef: true, browser: true */\n/*globals $, jQuery,_fnExternApiFunc,_fnInitalise,_fnLanguageProcess,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnGatherData,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxUpdateDraw,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnArrayCmp,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap*/\n\n(function($, window, document) {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Section - DataTables variables\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\t\n\t/*\n\t * Variable: dataTableSettings\n\t * Purpose:  Store the settings for each dataTables instance\n\t * Scope:    jQuery.fn\n\t */\n\t$.fn.dataTableSettings = [];\n\tvar _aoSettings = $.fn.dataTableSettings; /* Short reference for fast internal lookup */\n\t\n\t/*\n\t * Variable: dataTableExt\n\t * Purpose:  Container for customisable parts of DataTables\n\t * Scope:    jQuery.fn\n\t */\n\t$.fn.dataTableExt = {};\n\tvar _oExt = $.fn.dataTableExt;\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Section - DataTables extensible objects\n\t * \n\t * The _oExt object is used to provide an area where user dfined plugins can be \n\t * added to DataTables. The following properties of the object are used:\n\t *   oApi - Plug-in API functions\n\t *   aTypes - Auto-detection of types\n\t *   oSort - Sorting functions used by DataTables (based on the type)\n\t *   oPagination - Pagination functions for different input styles\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\t\n\t/*\n\t * Variable: sVersion\n\t * Purpose:  Version string for plug-ins to check compatibility\n\t * Scope:    jQuery.fn.dataTableExt\n\t * Notes:    Allowed format is a.b.c.d.e where:\n\t *   a:int, b:int, c:int, d:string(dev|beta), e:int. d and e are optional\n\t */\n\t_oExt.sVersion = \"1.7.4\";\n\t\n\t/*\n\t * Variable: sErrMode\n\t * Purpose:  How should DataTables report an error. Can take the value 'alert' or 'throw'\n\t * Scope:    jQuery.fn.dataTableExt\n\t */\n\t_oExt.sErrMode = \"alert\";\n\t\n\t/*\n\t * Variable: iApiIndex\n\t * Purpose:  Index for what 'this' index API functions should use\n\t * Scope:    jQuery.fn.dataTableExt\n\t */\n\t_oExt.iApiIndex = 0;\n\t\n\t/*\n\t * Variable: oApi\n\t * Purpose:  Container for plugin API functions\n\t * Scope:    jQuery.fn.dataTableExt\n\t */\n\t_oExt.oApi = { };\n\t\n\t/*\n\t * Variable: aFiltering\n\t * Purpose:  Container for plugin filtering functions\n\t * Scope:    jQuery.fn.dataTableExt\n\t */\n\t_oExt.afnFiltering = [ ];\n\t\n\t/*\n\t * Variable: aoFeatures\n\t * Purpose:  Container for plugin function functions\n\t * Scope:    jQuery.fn.dataTableExt\n\t * Notes:    Array of objects with the following parameters:\n\t *   fnInit: Function for initialisation of Feature. Takes oSettings and returns node\n\t *   cFeature: Character that will be matched in sDom - case sensitive\n\t *   sFeature: Feature name - just for completeness :-)\n\t */\n\t_oExt.aoFeatures = [ ];\n\t\n\t/*\n\t * Variable: ofnSearch\n\t * Purpose:  Container for custom filtering functions\n\t * Scope:    jQuery.fn.dataTableExt\n\t * Notes:    This is an object (the name should match the type) for custom filtering function,\n\t *   which can be used for live DOM checking or formatted text filtering\n\t */\n\t_oExt.ofnSearch = { };\n\t\n\t/*\n\t * Variable: afnSortData\n\t * Purpose:  Container for custom sorting data source functions\n\t * Scope:    jQuery.fn.dataTableExt\n\t * Notes:    Array (associative) of functions which is run prior to a column of this \n\t *   'SortDataType' being sorted upon.\n\t *   Function input parameters:\n\t *     object:oSettings-  DataTables settings object\n\t *     int:iColumn - Target column number\n\t *   Return value: Array of data which exactly matched the full data set size for the column to\n\t *     be sorted upon\n\t */\n\t_oExt.afnSortData = [ ];\n\t\n\t/*\n\t * Variable: oStdClasses\n\t * Purpose:  Storage for the various classes that DataTables uses\n\t * Scope:    jQuery.fn.dataTableExt\n\t */\n\t_oExt.oStdClasses = {\n\t\t/* Two buttons buttons */\n\t\t\"sPagePrevEnabled\": \"paginate_enabled_previous\",\n\t\t\"sPagePrevDisabled\": \"paginate_disabled_previous\",\n\t\t\"sPageNextEnabled\": \"paginate_enabled_next\",\n\t\t\"sPageNextDisabled\": \"paginate_disabled_next\",\n\t\t\"sPageJUINext\": \"\",\n\t\t\"sPageJUIPrev\": \"\",\n\t\t\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"paginate_active\",\n\t\t\"sPageButtonStaticDisabled\": \"paginate_button\",\n\t\t\"sPageFirst\": \"first\",\n\t\t\"sPagePrevious\": \"previous\",\n\t\t\"sPageNext\": \"next\",\n\t\t\"sPageLast\": \"last\",\n\t\t\n\t\t/* Stripping classes */\n\t\t\"sStripOdd\": \"odd\",\n\t\t\"sStripEven\": \"even\",\n\t\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\t\n\t\t/* Misc */\n\t\t\"sFooterTH\": \"\"\n\t};\n\t\n\t/*\n\t * Variable: oJUIClasses\n\t * Purpose:  Storage for the various classes that DataTables uses - jQuery UI suitable\n\t * Scope:    jQuery.fn.dataTableExt\n\t */\n\t_oExt.oJUIClasses = {\n\t\t/* Two buttons buttons */\n\t\t\"sPagePrevEnabled\": \"fg-button ui-button ui-state-default ui-corner-left\",\n\t\t\"sPagePrevDisabled\": \"fg-button ui-button ui-state-default ui-corner-left ui-state-disabled\",\n\t\t\"sPageNextEnabled\": \"fg-button ui-button ui-state-default ui-corner-right\",\n\t\t\"sPageNextDisabled\": \"fg-button ui-button ui-state-default ui-corner-right ui-state-disabled\",\n\t\t\"sPageJUINext\": \"ui-icon ui-icon-circle-arrow-e\",\n\t\t\"sPageJUIPrev\": \"ui-icon ui-icon-circle-arrow-w\",\n\t\t\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\": \"fg-button ui-button ui-state-default\",\n\t\t\"sPageButtonActive\": \"fg-button ui-button ui-state-default ui-state-disabled\",\n\t\t\"sPageButtonStaticDisabled\": \"fg-button ui-button ui-state-default ui-state-disabled\",\n\t\t\"sPageFirst\": \"first ui-corner-tl ui-corner-bl\",\n\t\t\"sPagePrevious\": \"previous\",\n\t\t\"sPageNext\": \"next\",\n\t\t\"sPageLast\": \"last ui-corner-tr ui-corner-br\",\n\t\t\n\t\t/* Stripping classes */\n\t\t\"sStripOdd\": \"odd\",\n\t\t\"sStripEven\": \"even\",\n\t\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"ui-state-default\",\n\t\t\"sSortDesc\": \"ui-state-default\",\n\t\t\"sSortable\": \"ui-state-default\",\n\t\t\"sSortableAsc\": \"ui-state-default\",\n\t\t\"sSortableDesc\": \"ui-state-default\",\n\t\t\"sSortableNone\": \"ui-state-default\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\t\"sSortJUIAsc\": \"css_right ui-icon ui-icon-triangle-1-n\",\n\t\t\"sSortJUIDesc\": \"css_right ui-icon ui-icon-triangle-1-s\",\n\t\t\"sSortJUI\": \"css_right ui-icon ui-icon-carat-2-n-s\",\n\t\t\"sSortJUIAscAllowed\": \"css_right ui-icon ui-icon-carat-1-n\",\n\t\t\"sSortJUIDescAllowed\": \"css_right ui-icon ui-icon-carat-1-s\",\n\t\t\"sSortJUIWrapper\": \"DataTables_sort_wrapper\",\n\t\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead ui-state-default\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot ui-state-default\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\t\n\t\t/* Misc */\n\t\t\"sFooterTH\": \"ui-state-default\"\n\t};\n\t\n\t/*\n\t * Variable: oPagination\n\t * Purpose:  Container for the various type of pagination that dataTables supports\n\t * Scope:    jQuery.fn.dataTableExt\n\t */\n\t_oExt.oPagination = {\n\t\t/*\n\t\t * Variable: two_button\n\t\t * Purpose:  Standard two button (forward/back) pagination\n\t \t * Scope:    jQuery.fn.dataTableExt.oPagination\n\t\t */\n\t\t\"two_button\": {\n\t\t\t/*\n\t\t\t * Function: oPagination.two_button.fnInit\n\t\t\t * Purpose:  Initalise dom elements required for pagination with forward/back buttons only\n\t\t\t * Returns:  -\n\t \t\t * Inputs:   object:oSettings - dataTables settings object\n\t     *           node:nPaging - the DIV which contains this pagination control\n\t\t\t *           function:fnCallbackDraw - draw function which must be called on update\n\t\t\t */\n\t\t\t\"fnInit\": function ( oSettings, nPaging, fnCallbackDraw )\n\t\t\t{\n\t\t\t\tvar nPrevious, nNext, nPreviousInner, nNextInner;\n\t\t\t\t\n\t\t\t\t/* Store the next and previous elements in the oSettings object as they can be very\n\t\t\t\t * usful for automation - particularly testing\n\t\t\t\t */\n\t\t\t\tif ( !oSettings.bJUI )\n\t\t\t\t{\n\t\t\t\t\tnPrevious = document.createElement( 'div' );\n\t\t\t\t\tnNext = document.createElement( 'div' );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnPrevious = document.createElement( 'a' );\n\t\t\t\t\tnNext = document.createElement( 'a' );\n\t\t\t\t\t\n\t\t\t\t\tnNextInner = document.createElement('span');\n\t\t\t\t\tnNextInner.className = oSettings.oClasses.sPageJUINext;\n\t\t\t\t\tnNext.appendChild( nNextInner );\n\t\t\t\t\t\n\t\t\t\t\tnPreviousInner = document.createElement('span');\n\t\t\t\t\tnPreviousInner.className = oSettings.oClasses.sPageJUIPrev;\n\t\t\t\t\tnPrevious.appendChild( nPreviousInner );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tnPrevious.className = oSettings.oClasses.sPagePrevDisabled;\n\t\t\t\tnNext.className = oSettings.oClasses.sPageNextDisabled;\n\t\t\t\t\n\t\t\t\tnPrevious.title = oSettings.oLanguage.oPaginate.sPrevious;\n\t\t\t\tnNext.title = oSettings.oLanguage.oPaginate.sNext;\n\t\t\t\t\n\t\t\t\tnPaging.appendChild( nPrevious );\n\t\t\t\tnPaging.appendChild( nNext );\n\t\t\t\t\n\t\t\t\t$(nPrevious).click( function() {\n\t\t\t\t\tif ( oSettings.oApi._fnPageChange( oSettings, \"previous\" ) )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Only draw when the page has actually changed */\n\t\t\t\t\t\tfnCallbackDraw( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\t\n\t\t\t\t$(nNext).click( function() {\n\t\t\t\t\tif ( oSettings.oApi._fnPageChange( oSettings, \"next\" ) )\n\t\t\t\t\t{\n\t\t\t\t\t\tfnCallbackDraw( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\t\n\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t$(nPrevious).bind( 'selectstart', function () { return false; } );\n\t\t\t\t$(nNext).bind( 'selectstart', function () { return false; } );\n\t\t\t\t\n\t\t\t\t/* ID the first elements only */\n\t\t\t\tif ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == \"undefined\" )\n\t\t\t\t{\n\t\t\t\t\tnPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );\n\t\t\t\t\tnPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );\n\t\t\t\t\tnNext.setAttribute( 'id', oSettings.sTableId+'_next' );\n\t\t\t\t}\n\t\t\t},\n\t\t\t\n\t\t\t/*\n\t\t\t * Function: oPagination.two_button.fnUpdate\n\t\t\t * Purpose:  Update the two button pagination at the end of the draw\n\t\t\t * Returns:  -\n\t \t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t\t *           function:fnCallbackDraw - draw function to call on page change\n\t\t\t */\n\t\t\t\"fnUpdate\": function ( oSettings, fnCallbackDraw )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aanFeatures.p )\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Loop over each instance of the pager */\n\t\t\t\tvar an = oSettings.aanFeatures.p;\n\t\t\t\tfor ( var i=0, iLen=an.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( an[i].childNodes.length !== 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\tan[i].childNodes[0].className = \n\t\t\t\t\t\t\t( oSettings._iDisplayStart === 0 ) ? \n\t\t\t\t\t\t\toSettings.oClasses.sPagePrevDisabled : oSettings.oClasses.sPagePrevEnabled;\n\t\t\t\t\t\t\n\t\t\t\t\t\tan[i].childNodes[1].className = \n\t\t\t\t\t\t\t( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ? \n\t\t\t\t\t\t\toSettings.oClasses.sPageNextDisabled : oSettings.oClasses.sPageNextEnabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\n\t\t\n\t\t/*\n\t\t * Variable: iFullNumbersShowPages\n\t\t * Purpose:  Change the number of pages which can be seen\n\t \t * Scope:    jQuery.fn.dataTableExt.oPagination\n\t\t */\n\t\t\"iFullNumbersShowPages\": 5,\n\t\t\n\t\t/*\n\t\t * Variable: full_numbers\n\t\t * Purpose:  Full numbers pagination\n\t \t * Scope:    jQuery.fn.dataTableExt.oPagination\n\t\t */\n\t\t\"full_numbers\": {\n\t\t\t/*\n\t\t\t * Function: oPagination.full_numbers.fnInit\n\t\t\t * Purpose:  Initalise dom elements required for pagination with a list of the pages\n\t\t\t * Returns:  -\n\t \t\t * Inputs:   object:oSettings - dataTables settings object\n\t     *           node:nPaging - the DIV which contains this pagination control\n\t\t\t *           function:fnCallbackDraw - draw function which must be called on update\n\t\t\t */\n\t\t\t\"fnInit\": function ( oSettings, nPaging, fnCallbackDraw )\n\t\t\t{\n\t\t\t\tvar nFirst = document.createElement( 'span' );\n\t\t\t\tvar nPrevious = document.createElement( 'span' );\n\t\t\t\tvar nList = document.createElement( 'span' );\n\t\t\t\tvar nNext = document.createElement( 'span' );\n\t\t\t\tvar nLast = document.createElement( 'span' );\n\t\t\t\t\n\t\t\t\tnFirst.innerHTML = oSettings.oLanguage.oPaginate.sFirst;\n\t\t\t\tnPrevious.innerHTML = oSettings.oLanguage.oPaginate.sPrevious;\n\t\t\t\tnNext.innerHTML = oSettings.oLanguage.oPaginate.sNext;\n\t\t\t\tnLast.innerHTML = oSettings.oLanguage.oPaginate.sLast;\n\t\t\t\t\n\t\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\tnFirst.className = oClasses.sPageButton+\" \"+oClasses.sPageFirst;\n\t\t\t\tnPrevious.className = oClasses.sPageButton+\" \"+oClasses.sPagePrevious;\n\t\t\t\tnNext.className= oClasses.sPageButton+\" \"+oClasses.sPageNext;\n\t\t\t\tnLast.className = oClasses.sPageButton+\" \"+oClasses.sPageLast;\n\t\t\t\t\n\t\t\t\tnPaging.appendChild( nFirst );\n\t\t\t\tnPaging.appendChild( nPrevious );\n\t\t\t\tnPaging.appendChild( nList );\n\t\t\t\tnPaging.appendChild( nNext );\n\t\t\t\tnPaging.appendChild( nLast );\n\t\t\t\t\n\t\t\t\t$(nFirst).click( function () {\n\t\t\t\t\tif ( oSettings.oApi._fnPageChange( oSettings, \"first\" ) )\n\t\t\t\t\t{\n\t\t\t\t\t\tfnCallbackDraw( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\t\n\t\t\t\t$(nPrevious).click( function() {\n\t\t\t\t\tif ( oSettings.oApi._fnPageChange( oSettings, \"previous\" ) )\n\t\t\t\t\t{\n\t\t\t\t\t\tfnCallbackDraw( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\t\n\t\t\t\t$(nNext).click( function() {\n\t\t\t\t\tif ( oSettings.oApi._fnPageChange( oSettings, \"next\" ) )\n\t\t\t\t\t{\n\t\t\t\t\t\tfnCallbackDraw( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\t\n\t\t\t\t$(nLast).click( function() {\n\t\t\t\t\tif ( oSettings.oApi._fnPageChange( oSettings, \"last\" ) )\n\t\t\t\t\t{\n\t\t\t\t\t\tfnCallbackDraw( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\t\n\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t$('span', nPaging)\n\t\t\t\t\t.bind( 'mousedown', function () { return false; } )\n\t\t\t\t\t.bind( 'selectstart', function () { return false; } );\n\t\t\t\t\n\t\t\t\t/* ID the first elements only */\n\t\t\t\tif ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == \"undefined\" )\n\t\t\t\t{\n\t\t\t\t\tnPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );\n\t\t\t\t\tnFirst.setAttribute( 'id', oSettings.sTableId+'_first' );\n\t\t\t\t\tnPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );\n\t\t\t\t\tnNext.setAttribute( 'id', oSettings.sTableId+'_next' );\n\t\t\t\t\tnLast.setAttribute( 'id', oSettings.sTableId+'_last' );\n\t\t\t\t}\n\t\t\t},\n\t\t\t\n\t\t\t/*\n\t\t\t * Function: oPagination.full_numbers.fnUpdate\n\t\t\t * Purpose:  Update the list of page buttons shows\n\t\t\t * Returns:  -\n\t \t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t\t *           function:fnCallbackDraw - draw function to call on page change\n\t\t\t */\n\t\t\t\"fnUpdate\": function ( oSettings, fnCallbackDraw )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aanFeatures.p )\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar iPageCount = _oExt.oPagination.iFullNumbersShowPages;\n\t\t\t\tvar iPageCountHalf = Math.floor(iPageCount / 2);\n\t\t\t\tvar iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);\n\t\t\t\tvar iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;\n\t\t\t\tvar sList = \"\";\n\t\t\t\tvar iStartButton, iEndButton, i, iLen;\n\t\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\t\n\t\t\t\t/* Pages calculation */\n\t\t\t\tif (iPages < iPageCount)\n\t\t\t\t{\n\t\t\t\t\tiStartButton = 1;\n\t\t\t\t\tiEndButton = iPages;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (iCurrentPage <= iPageCountHalf)\n\t\t\t\t\t{\n\t\t\t\t\t\tiStartButton = 1;\n\t\t\t\t\t\tiEndButton = iPageCount;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (iCurrentPage >= (iPages - iPageCountHalf))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tiStartButton = iPages - iPageCount + 1;\n\t\t\t\t\t\t\tiEndButton = iPages;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tiStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;\n\t\t\t\t\t\t\tiEndButton = iStartButton + iPageCount - 1;\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\t/* Build the dynamic list */\n\t\t\t\tfor ( i=iStartButton ; i<=iEndButton ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( iCurrentPage != i )\n\t\t\t\t\t{\n\t\t\t\t\t\tsList += '<span class=\"'+oClasses.sPageButton+'\">'+i+'</span>';\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tsList += '<span class=\"'+oClasses.sPageButtonActive+'\">'+i+'</span>';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Loop over each instance of the pager */\n\t\t\t\tvar an = oSettings.aanFeatures.p;\n\t\t\t\tvar anButtons, anStatic, nPaginateList;\n\t\t\t\tvar fnClick = function() {\n\t\t\t\t\t/* Use the information in the element to jump to the required page */\n\t\t\t\t\tvar iTarget = (this.innerHTML * 1) - 1;\n\t\t\t\t\toSettings._iDisplayStart = iTarget * oSettings._iDisplayLength;\n\t\t\t\t\tfnCallbackDraw( oSettings );\n\t\t\t\t\treturn false;\n\t\t\t\t};\n\t\t\t\tvar fnFalse = function () { return false; };\n\t\t\t\t\n\t\t\t\tfor ( i=0, iLen=an.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( an[i].childNodes.length === 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t/* Build up the dynamic list forst - html and listeners */\n\t\t\t\t\tvar qjPaginateList = $('span:eq(2)', an[i]);\n\t\t\t\t\tqjPaginateList.html( sList );\n\t\t\t\t\t$('span', qjPaginateList).click( fnClick ).bind( 'mousedown', fnFalse )\n\t\t\t\t\t\t.bind( 'selectstart', fnFalse );\n\t\t\t\t\t\n\t\t\t\t\t/* Update the 'premanent botton's classes */\n\t\t\t\t\tanButtons = an[i].getElementsByTagName('span');\n\t\t\t\t\tanStatic = [\n\t\t\t\t\t\tanButtons[0], anButtons[1], \n\t\t\t\t\t\tanButtons[anButtons.length-2], anButtons[anButtons.length-1]\n\t\t\t\t\t];\n\t\t\t\t\t$(anStatic).removeClass( oClasses.sPageButton+\" \"+oClasses.sPageButtonActive+\" \"+oClasses.sPageButtonStaticDisabled );\n\t\t\t\t\tif ( iCurrentPage == 1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tanStatic[0].className += \" \"+oClasses.sPageButtonStaticDisabled;\n\t\t\t\t\t\tanStatic[1].className += \" \"+oClasses.sPageButtonStaticDisabled;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tanStatic[0].className += \" \"+oClasses.sPageButton;\n\t\t\t\t\t\tanStatic[1].className += \" \"+oClasses.sPageButton;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif ( iPages === 0 || iCurrentPage == iPages || oSettings._iDisplayLength == -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tanStatic[2].className += \" \"+oClasses.sPageButtonStaticDisabled;\n\t\t\t\t\t\tanStatic[3].className += \" \"+oClasses.sPageButtonStaticDisabled;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tanStatic[2].className += \" \"+oClasses.sPageButton;\n\t\t\t\t\t\tanStatic[3].className += \" \"+oClasses.sPageButton;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\t\n\t/*\n\t * Variable: oSort\n\t * Purpose:  Wrapper for the sorting functions that can be used in DataTables\n\t * Scope:    jQuery.fn.dataTableExt\n\t * Notes:    The functions provided in this object are basically standard javascript sort\n\t *   functions - they expect two inputs which they then compare and then return a priority\n\t *   result. For each sort method added, two functions need to be defined, an ascending sort and\n\t *   a descending sort.\n\t */\n\t_oExt.oSort = {\n\t\t/*\n\t\t * text sorting\n\t\t */\n\t\t\"string-asc\": function ( a, b )\n\t\t{\n\t\t\tvar x = a.toLowerCase();\n\t\t\tvar y = b.toLowerCase();\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\t\n\t\t\"string-desc\": function ( a, b )\n\t\t{\n\t\t\tvar x = a.toLowerCase();\n\t\t\tvar y = b.toLowerCase();\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t},\n\t\t\n\t\t\n\t\t/*\n\t\t * html sorting (ignore html tags)\n\t\t */\n\t\t\"html-asc\": function ( a, b )\n\t\t{\n\t\t\tvar x = a.replace( /<.*?>/g, \"\" ).toLowerCase();\n\t\t\tvar y = b.replace( /<.*?>/g, \"\" ).toLowerCase();\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\t\n\t\t\"html-desc\": function ( a, b )\n\t\t{\n\t\t\tvar x = a.replace( /<.*?>/g, \"\" ).toLowerCase();\n\t\t\tvar y = b.replace( /<.*?>/g, \"\" ).toLowerCase();\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t},\n\t\t\n\t\t\n\t\t/*\n\t\t * date sorting\n\t\t */\n\t\t\"date-asc\": function ( a, b )\n\t\t{\n\t\t\tvar x = Date.parse( a );\n\t\t\tvar y = Date.parse( b );\n\t\t\t\n\t\t\tif ( isNaN(x) || x===\"\" )\n\t\t\t{\n    \t\tx = Date.parse( \"01/01/1970 00:00:00\" );\n\t\t\t}\n\t\t\tif ( isNaN(y) || y===\"\" )\n\t\t\t{\n\t\t\t\ty =\tDate.parse( \"01/01/1970 00:00:00\" );\n\t\t\t}\n\t\t\t\n\t\t\treturn x - y;\n\t\t},\n\t\t\n\t\t\"date-desc\": function ( a, b )\n\t\t{\n\t\t\tvar x = Date.parse( a );\n\t\t\tvar y = Date.parse( b );\n\t\t\t\n\t\t\tif ( isNaN(x) || x===\"\" )\n\t\t\t{\n    \t\tx = Date.parse( \"01/01/1970 00:00:00\" );\n\t\t\t}\n\t\t\tif ( isNaN(y) || y===\"\" )\n\t\t\t{\n\t\t\t\ty =\tDate.parse( \"01/01/1970 00:00:00\" );\n\t\t\t}\n\t\t\t\n\t\t\treturn y - x;\n\t\t},\n\t\t\n\t\t\n\t\t/*\n\t\t * numerical sorting\n\t\t */\n\t\t\"numeric-asc\": function ( a, b )\n\t\t{\n\t\t\tvar x = (a==\"-\" || a===\"\") ? 0 : a*1;\n\t\t\tvar y = (b==\"-\" || b===\"\") ? 0 : b*1;\n\t\t\treturn x - y;\n\t\t},\n\t\t\n\t\t\"numeric-desc\": function ( a, b )\n\t\t{\n\t\t\tvar x = (a==\"-\" || a===\"\") ? 0 : a*1;\n\t\t\tvar y = (b==\"-\" || b===\"\") ? 0 : b*1;\n\t\t\treturn y - x;\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * Variable: aTypes\n\t * Purpose:  Container for the various type of type detection that dataTables supports\n\t * Scope:    jQuery.fn.dataTableExt\n\t * Notes:    The functions in this array are expected to parse a string to see if it is a data\n\t *   type that it recognises. If so then the function should return the name of the type (a\n\t *   corresponding sort function should be defined!), if the type is not recognised then the\n\t *   function should return null such that the parser and move on to check the next type.\n\t *   Note that ordering is important in this array - the functions are processed linearly,\n\t *   starting at index 0.\n\t *   Note that the input for these functions is always a string! It cannot be any other data\n\t *   type\n\t */\n\t_oExt.aTypes = [\n\t\t/*\n\t\t * Function: -\n\t\t * Purpose:  Check to see if a string is numeric\n\t\t * Returns:  string:'numeric' or null\n\t\t * Inputs:   string:sText - string to check\n\t\t */\n\t\tfunction ( sData )\n\t\t{\n\t\t\t/* Allow zero length strings as a number */\n\t\t\tif ( sData.length === 0 )\n\t\t\t{\n\t\t\t\treturn 'numeric';\n\t\t\t}\n\t\t\t\n\t\t\tvar sValidFirstChars = \"0123456789-\";\n\t\t\tvar sValidChars = \"0123456789.\";\n\t\t\tvar Char;\n\t\t\tvar bDecimal = false;\n\t\t\t\n\t\t\t/* Check for a valid first char (no period and allow negatives) */\n\t\t\tChar = sData.charAt(0); \n\t\t\tif (sValidFirstChars.indexOf(Char) == -1) \n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\t/* Check all the other characters are valid */\n\t\t\tfor ( var i=1 ; i<sData.length ; i++ ) \n\t\t\t{\n\t\t\t\tChar = sData.charAt(i); \n\t\t\t\tif (sValidChars.indexOf(Char) == -1) \n\t\t\t\t{\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Only allowed one decimal place... */\n\t\t\t\tif ( Char == \".\" )\n\t\t\t\t{\n\t\t\t\t\tif ( bDecimal )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tbDecimal = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn 'numeric';\n\t\t},\n\t\t\n\t\t/*\n\t\t * Function: -\n\t\t * Purpose:  Check to see if a string is actually a formatted date\n\t\t * Returns:  string:'date' or null\n\t\t * Inputs:   string:sText - string to check\n\t\t */\n\t\tfunction ( sData )\n\t\t{\n\t\t\tvar iParse = Date.parse(sData);\n\t\t\tif ( (iParse !== null && !isNaN(iParse)) || sData.length === 0 )\n\t\t\t{\n\t\t\t\treturn 'date';\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\t\n\t\t/*\n\t\t * Function: -\n\t\t * Purpose:  Check to see if a string should be treated as an HTML string\n\t\t * Returns:  string:'html' or null\n\t\t * Inputs:   string:sText - string to check\n\t\t */\n\t\tfunction ( sData )\n\t\t{\n\t\t\tif ( sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )\n\t\t\t{\n\t\t\t\treturn 'html';\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t];\n\t\n\t/*\n\t * Function: fnVersionCheck\n\t * Purpose:  Check a version string against this version of DataTables. Useful for plug-ins\n\t * Returns:  bool:true -this version of DataTables is greater or equal to the required version\n\t *                false -this version of DataTales is not suitable\n\t * Inputs:   string:sVersion - the version to check against. May be in the following formats:\n\t *             \"a\", \"a.b\" or \"a.b.c\"\n\t * Notes:    This function will only check the first three parts of a version string. It is\n\t *   assumed that beta and dev versions will meet the requirements. This might change in future\n\t */\n\t_oExt.fnVersionCheck = function( sVersion )\n\t{\n\t\t/* This is cheap, but very effective */\n\t\tvar fnZPad = function (Zpad, count)\n\t\t{\n\t\t\twhile(Zpad.length < count) {\n\t\t\t\tZpad += '0';\n\t\t\t}\n\t\t\treturn Zpad;\n\t\t};\n\t\tvar aThis = _oExt.sVersion.split('.');\n\t\tvar aThat = sVersion.split('.');\n\t\tvar sThis = '', sThat = '';\n\t\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tsThis += fnZPad( aThis[i], 3 );\n\t\t\tsThat += fnZPad( aThat[i], 3 );\n\t\t}\n\t\t\n\t\treturn parseInt(sThis, 10) >= parseInt(sThat, 10);\n\t};\n\t\n\t/*\n\t * Variable: _oExternConfig\n\t * Purpose:  Store information for DataTables to access globally about other instances\n\t * Scope:    jQuery.fn.dataTableExt\n\t */\n\t_oExt._oExternConfig = {\n\t\t/* int:iNextUnique - next unique number for an instance */\n\t\t\"iNextUnique\": 0\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Section - DataTables prototype\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\t\n\t/*\n\t * Function: dataTable\n\t * Purpose:  DataTables information\n\t * Returns:  -\n\t * Inputs:   object:oInit - initalisation options for the table\n\t */\n\t$.fn.dataTable = function( oInit )\n\t{\n\t\t/*\n\t\t * Function: classSettings\n\t\t * Purpose:  Settings container function for all 'class' properties which are required\n\t\t *   by dataTables\n\t\t * Returns:  -\n\t\t * Inputs:   -\n\t\t */\n\t\tfunction classSettings ()\n\t\t{\n\t\t\tthis.fnRecordsTotal = function ()\n\t\t\t{\n\t\t\t\tif ( this.oFeatures.bServerSide ) {\n\t\t\t\t\treturn parseInt(this._iRecordsTotal, 10);\n\t\t\t\t} else {\n\t\t\t\t\treturn this.aiDisplayMaster.length;\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\tthis.fnRecordsDisplay = function ()\n\t\t\t{\n\t\t\t\tif ( this.oFeatures.bServerSide ) {\n\t\t\t\t\treturn parseInt(this._iRecordsDisplay, 10);\n\t\t\t\t} else {\n\t\t\t\t\treturn this.aiDisplay.length;\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\tthis.fnDisplayEnd = function ()\n\t\t\t{\n\t\t\t\tif ( this.oFeatures.bServerSide ) {\n\t\t\t\t\tif ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {\n\t\t\t\t\t\treturn this._iDisplayStart+this.aiDisplay.length;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn Math.min( this._iDisplayStart+this._iDisplayLength, \n\t\t\t\t\t\t\tthis._iRecordsDisplay );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn this._iDisplayEnd;\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: oInstance\n\t\t\t * Purpose:  The DataTables object for this table\n\t\t\t * Scope:    jQuery.dataTable.classSettings \n\t\t\t */\n\t\t\tthis.oInstance = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: sInstance\n\t\t\t * Purpose:  Unique idendifier for each instance of the DataTables object\n\t\t\t * Scope:    jQuery.dataTable.classSettings \n\t\t\t */\n\t\t\tthis.sInstance = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: oFeatures\n\t\t\t * Purpose:  Indicate the enablement of key dataTable features\n\t\t\t * Scope:    jQuery.dataTable.classSettings \n\t\t\t */\n\t\t\tthis.oFeatures = {\n\t\t\t\t\"bPaginate\": true,\n\t\t\t\t\"bLengthChange\": true,\n\t\t\t\t\"bFilter\": true,\n\t\t\t\t\"bSort\": true,\n\t\t\t\t\"bInfo\": true,\n\t\t\t\t\"bAutoWidth\": true,\n\t\t\t\t\"bProcessing\": false,\n\t\t\t\t\"bSortClasses\": true,\n\t\t\t\t\"bStateSave\": false,\n\t\t\t\t\"bServerSide\": false\n\t\t\t};\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: oScroll\n\t\t\t * Purpose:  Container for scrolling options\n\t\t\t * Scope:    jQuery.dataTable.classSettings \n\t\t\t */\n\t\t\tthis.oScroll = {\n\t\t\t\t\"sX\": \"\",\n\t\t\t\t\"sXInner\": \"\",\n\t\t\t\t\"sY\": \"\",\n\t\t\t\t\"bCollapse\": false,\n\t\t\t\t\"bInfinite\": false,\n\t\t\t\t\"iLoadGap\": 100,\n\t\t\t\t\"iBarWidth\": 0\n\t\t\t};\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aanFeatures\n\t\t\t * Purpose:  Array referencing the nodes which are used for the features\n\t\t\t * Scope:    jQuery.dataTable.classSettings \n\t\t\t * Notes:    The parameters of this object match what is allowed by sDom - i.e.\n\t\t\t *   'l' - Length changing\n\t\t\t *   'f' - Filtering input\n\t\t\t *   't' - The table!\n\t\t\t *   'i' - Information\n\t\t\t *   'p' - Pagination\n\t\t\t *   'r' - pRocessing\n\t\t\t */\n\t\t\tthis.aanFeatures = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: oLanguage\n\t\t\t * Purpose:  Store the language strings used by dataTables\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Notes:    The words in the format _VAR_ are variables which are dynamically replaced\n\t\t\t *   by javascript\n\t\t\t */\n\t\t\tthis.oLanguage = {\n\t\t\t\t\"sProcessing\": \"Processing...\",\n\t\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\t\t\t\"sZeroRecords\": \"No matching records found\",\n\t\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\t\t\t\"sInfoPostFix\": \"\",\n\t\t\t\t\"sSearch\": \"Search:\",\n\t\t\t\t\"sUrl\": \"\",\n\t\t\t\t\"oPaginate\": {\n\t\t\t\t\t\"sFirst\":    \"First\",\n\t\t\t\t\t\"sPrevious\": \"Previous\",\n\t\t\t\t\t\"sNext\":     \"Next\",\n\t\t\t\t\t\"sLast\":     \"Last\"\n\t\t\t\t},\n\t\t\t\t\"fnInfoCallback\": null\n\t\t\t};\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aoData\n\t\t\t * Purpose:  Store data information\n\t\t\t * Scope:    jQuery.dataTable.classSettings \n\t\t\t * Notes:    This is an array of objects with the following parameters:\n\t\t\t *   int: _iId - internal id for tracking\n\t\t\t *   array: _aData - internal data - used for sorting / filtering etc\n\t\t\t *   node: nTr - display node\n\t\t\t *   array node: _anHidden - hidden TD nodes\n\t\t\t *   string: _sRowStripe\n\t\t\t */\n\t\t\tthis.aoData = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aiDisplay\n\t\t\t * Purpose:  Array of indexes which are in the current display (after filtering etc)\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.aiDisplay = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aiDisplayMaster\n\t\t\t * Purpose:  Array of indexes for display - no filtering\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.aiDisplayMaster = [];\n\t\t\t\t\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aoColumns\n\t\t\t * Purpose:  Store information about each column that is in use\n\t\t\t * Scope:    jQuery.dataTable.classSettings \n\t\t\t */\n\t\t\tthis.aoColumns = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: iNextId\n\t\t\t * Purpose:  Store the next unique id to be used for a new row\n\t\t\t * Scope:    jQuery.dataTable.classSettings \n\t\t\t */\n\t\t\tthis.iNextId = 0;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: asDataSearch\n\t\t\t * Purpose:  Search data array for regular expression searching\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.asDataSearch = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: oPreviousSearch\n\t\t\t * Purpose:  Store the previous search incase we want to force a re-search\n\t\t\t *   or compare the old search to a new one\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.oPreviousSearch = {\n\t\t\t\t\"sSearch\": \"\",\n\t\t\t\t\"bRegex\": false,\n\t\t\t\t\"bSmart\": true\n\t\t\t};\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aoPreSearchCols\n\t\t\t * Purpose:  Store the previous search for each column\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.aoPreSearchCols = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aaSorting\n\t\t\t * Purpose:  Sorting information\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Notes:    Index 0 - column number\n\t\t\t *           Index 1 - current sorting direction\n\t\t\t *           Index 2 - index of asSorting for this column\n\t\t\t */\n\t\t\tthis.aaSorting = [ [0, 'asc', 0] ];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aaSortingFixed\n\t\t\t * Purpose:  Sorting information that is always applied\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.aaSortingFixed = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: asStripClasses\n\t\t\t * Purpose:  Classes to use for the striping of a table\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.asStripClasses = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: asDestoryStrips\n\t\t\t * Purpose:  If restoring a table - we should restore it's striping classes as well\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.asDestoryStrips = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: sDestroyWidth\n\t\t\t * Purpose:  If restoring a table - we should restore it's width\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.sDestroyWidth = 0;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: fnRowCallback\n\t\t\t * Purpose:  Call this function every time a row is inserted (draw)\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.fnRowCallback = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: fnHeaderCallback\n\t\t\t * Purpose:  Callback function for the header on each draw\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.fnHeaderCallback = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: fnFooterCallback\n\t\t\t * Purpose:  Callback function for the footer on each draw\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.fnFooterCallback = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aoDrawCallback\n\t\t\t * Purpose:  Array of callback functions for draw callback functions\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Notes:    Each array element is an object with the following parameters:\n\t\t\t *   function:fn - function to call\n\t\t\t *   string:sName - name callback (feature). useful for arranging array\n\t\t\t */\n\t\t\tthis.aoDrawCallback = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: fnInitComplete\n\t\t\t * Purpose:  Callback function for when the table has been initalised\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.fnInitComplete = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: sTableId\n\t\t\t * Purpose:  Cache the table ID for quick access\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.sTableId = \"\";\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: nTable\n\t\t\t * Purpose:  Cache the table node for quick access\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.nTable = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: nTHead\n\t\t\t * Purpose:  Permanent ref to the thead element\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.nTHead = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: nTFoot\n\t\t\t * Purpose:  Permanent ref to the tfoot element - if it exists\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.nTFoot = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: nTBody\n\t\t\t * Purpose:  Permanent ref to the tbody element\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.nTBody = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: nTableWrapper\n\t\t\t * Purpose:  Cache the wrapper node (contains all DataTables controlled elements)\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.nTableWrapper = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: bInitialised\n\t\t\t * Purpose:  Indicate if all required information has been read in\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.bInitialised = false;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aoOpenRows\n\t\t\t * Purpose:  Information about open rows\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Notes:    Has the parameters 'nTr' and 'nParent'\n\t\t\t */\n\t\t\tthis.aoOpenRows = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: sDom\n\t\t\t * Purpose:  Dictate the positioning that the created elements will take\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Notes:    \n\t\t\t *   The following options are allowed:\n\t\t\t *     'l' - Length changing\n\t\t\t *     'f' - Filtering input\n\t\t\t *     't' - The table!\n\t\t\t *     'i' - Information\n\t\t\t *     'p' - Pagination\n\t\t\t *     'r' - pRocessing\n\t\t\t *   The following constants are allowed:\n\t\t\t *     'H' - jQueryUI theme \"header\" classes\n\t\t\t *     'F' - jQueryUI theme \"footer\" classes\n\t\t\t *   The following syntax is expected:\n\t\t\t *     '<' and '>' - div elements\n\t\t\t *     '<\"class\" and '>' - div with a class\n\t\t\t *   Examples:\n\t\t\t *     '<\"wrapper\"flipt>', '<lf<t>ip>'\n\t\t\t */\n\t\t\tthis.sDom = 'lfrtip';\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: sPaginationType\n\t\t\t * Purpose:  Note which type of sorting should be used\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.sPaginationType = \"two_button\";\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: iCookieDuration\n\t\t\t * Purpose:  The cookie duration (for bStateSave) in seconds - default 2 hours\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.iCookieDuration = 60 * 60 * 2;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: sCookiePrefix\n\t\t\t * Purpose:  The cookie name prefix\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.sCookiePrefix = \"SpryMedia_DataTables_\";\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: fnCookieCallback\n\t\t\t * Purpose:  Callback function for cookie creation\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.fnCookieCallback = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aoStateSave\n\t\t\t * Purpose:  Array of callback functions for state saving\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Notes:    Each array element is an object with the following parameters:\n\t\t\t *   function:fn - function to call. Takes two parameters, oSettings and the JSON string to\n\t\t\t *     save that has been thus far created. Returns a JSON string to be inserted into a \n\t\t\t *     json object (i.e. '\"param\": [ 0, 1, 2]')\n\t\t\t *   string:sName - name of callback\n\t\t\t */\n\t\t\tthis.aoStateSave = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aoStateLoad\n\t\t\t * Purpose:  Array of callback functions for state loading\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Notes:    Each array element is an object with the following parameters:\n\t\t\t *   function:fn - function to call. Takes two parameters, oSettings and the object stored.\n\t\t\t *     May return false to cancel state loading.\n\t\t\t *   string:sName - name of callback\n\t\t\t */\n\t\t\tthis.aoStateLoad = [];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: oLoadedState\n\t\t\t * Purpose:  State that was loaded from the cookie. Useful for back reference\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.oLoadedState = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: sAjaxSource\n\t\t\t * Purpose:  Source url for AJAX data for the table\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.sAjaxSource = null;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: bAjaxDataGet\n\t\t\t * Purpose:  Note if draw should be blocked while getting data\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.bAjaxDataGet = true;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: fnServerData\n\t\t\t * Purpose:  Function to get the server-side data - can be overruled by the developer\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.fnServerData = function ( url, data, callback ) {\n\t\t\t\t$.ajax( {\n\t\t\t\t\t\"url\": url,\n\t\t\t\t\t\"data\": data,\n\t\t\t\t\t\"success\": callback,\n\t\t\t\t\t\"dataType\": \"json\",\n\t\t\t\t\t\"cache\": false,\n\t\t\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t\talert( \"DataTables warning: JSON data from server could not be parsed. \"+\n\t\t\t\t\t\t\t\t\"This is caused by a JSON formatting error.\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t};\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: fnFormatNumber\n\t\t\t * Purpose:  Format numbers for display\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.fnFormatNumber = function ( iIn )\n\t\t\t{\n\t\t\t\tif ( iIn < 1000 )\n\t\t\t\t{\n\t\t\t\t\t/* A small optimisation for what is likely to be the vast majority of use cases */\n\t\t\t\t\treturn iIn;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tvar s=(iIn+\"\"), a=s.split(\"\"), out=\"\", iLen=s.length;\n\t\t\t\t\t\n\t\t\t\t\tfor ( var i=0 ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( i%3 === 0 && i !== 0 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tout = ','+out;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tout = a[iLen-i-1]+out;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn out;\n\t\t\t};\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: aLengthMenu\n\t\t\t * Purpose:  List of options that can be used for the user selectable length menu\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Note:     This varaible can take for form of a 1D array, in which case the value and the \n\t\t\t *   displayed value in the menu are the same, or a 2D array in which case the value comes\n\t\t\t *   from the first array, and the displayed value to the end user comes from the second\n\t\t\t *   array. 2D example: [ [ 10, 25, 50, 100, -1 ], [ 10, 25, 50, 100, 'All' ] ];\n\t\t\t */\n\t\t\tthis.aLengthMenu = [ 10, 25, 50, 100 ];\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: iDraw\n\t\t\t * Purpose:  Counter for the draws that the table does. Also used as a tracker for\n\t\t\t *   server-side processing\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.iDraw = 0;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: bDrawing\n\t\t\t * Purpose:  Indicate if a redraw is being done - useful for Ajax\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.bDrawing = 0;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: iDrawError\n\t\t\t * Purpose:  Last draw error\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.iDrawError = -1;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: _iDisplayLength, _iDisplayStart, _iDisplayEnd\n\t\t\t * Purpose:  Display length variables\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Notes:    These variable must NOT be used externally to get the data length. Rather, use\n\t\t\t *   the fnRecordsTotal() (etc) functions.\n\t\t\t */\n\t\t\tthis._iDisplayLength = 10;\n\t\t\tthis._iDisplayStart = 0;\n\t\t\tthis._iDisplayEnd = 10;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: _iRecordsTotal, _iRecordsDisplay\n\t\t\t * Purpose:  Display length variables used for server side processing\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t * Notes:    These variable must NOT be used externally to get the data length. Rather, use\n\t\t\t *   the fnRecordsTotal() (etc) functions.\n\t\t\t */\n\t\t\tthis._iRecordsTotal = 0;\n\t\t\tthis._iRecordsDisplay = 0;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: bJUI\n\t\t\t * Purpose:  Should we add the markup needed for jQuery UI theming?\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.bJUI = false;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: bJUI\n\t\t\t * Purpose:  Should we add the markup needed for jQuery UI theming?\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.oClasses = _oExt.oStdClasses;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: bFiltered and bSorted\n\t\t\t * Purpose:  Flags to allow callback functions to see what actions have been performed\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.bFiltered = false;\n\t\t\tthis.bSorted = false;\n\t\t\t\n\t\t\t/*\n\t\t\t * Variable: oInit\n\t\t\t * Purpose:  Initialisation object that is used for the table\n\t\t\t * Scope:    jQuery.dataTable.classSettings\n\t\t\t */\n\t\t\tthis.oInit = null;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Variable: oApi\n\t\t * Purpose:  Container for publicly exposed 'private' functions\n\t\t * Scope:    jQuery.dataTable\n\t\t */\n\t\tthis.oApi = {};\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - API functions\n\t\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\t\t\n\t\t/*\n\t\t * Function: fnDraw\n\t\t * Purpose:  Redraw the table\n\t\t * Returns:  -\n\t\t * Inputs:   bool:bComplete - Refilter and resort (if enabled) the table before the draw.\n\t\t *             Optional: default - true\n\t\t */\n\t\tthis.fnDraw = function( bComplete )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\tif ( typeof bComplete != 'undefined' && bComplete === false )\n\t\t\t{\n\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t_fnDraw( oSettings );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_fnReDraw( oSettings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnFilter\n\t\t * Purpose:  Filter the input based on data\n\t\t * Returns:  -\n\t\t * Inputs:   string:sInput - string to filter the table on\n\t\t *           int:iColumn - optional - column to limit filtering to\n\t\t *           bool:bRegex - optional - treat as regular expression or not - default false\n\t\t *           bool:bSmart - optional - perform smart filtering or not - default true\n\t\t *           bool:bShowGlobal - optional - show the input global filter in it's input box(es)\n\t\t *              - default true\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\t\n\t\t\tif ( !oSettings.oFeatures.bFilter )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif ( typeof bRegex == 'undefined' )\n\t\t\t{\n\t\t\t\tbRegex = false;\n\t\t\t}\n\t\t\t\n\t\t\tif ( typeof bSmart == 'undefined' )\n\t\t\t{\n\t\t\t\tbSmart = true;\n\t\t\t}\n\t\t\t\n\t\t\tif ( typeof bShowGlobal == 'undefined' )\n\t\t\t{\n\t\t\t\tbShowGlobal = true;\n\t\t\t}\n\t\t\t\n\t\t\tif ( typeof iColumn == \"undefined\" || iColumn === null )\n\t\t\t{\n\t\t\t\t/* Global filter */\n\t\t\t\t_fnFilterComplete( oSettings, {\n\t\t\t\t\t\"sSearch\":sInput,\n\t\t\t\t\t\"bRegex\": bRegex,\n\t\t\t\t\t\"bSmart\": bSmart\n\t\t\t\t}, 1 );\n\t\t\t\t\n\t\t\t\tif ( bShowGlobal && typeof oSettings.aanFeatures.f != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\tvar n = oSettings.aanFeatures.f;\n\t\t\t\t\tfor ( var i=0, iLen=n.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t$('input', n[i]).val( sInput );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Single column filter */\n\t\t\t\toSettings.aoPreSearchCols[ iColumn ].sSearch = sInput;\n\t\t\t\toSettings.aoPreSearchCols[ iColumn ].bRegex = bRegex;\n\t\t\t\toSettings.aoPreSearchCols[ iColumn ].bSmart = bSmart;\n\t\t\t\t_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );\n\t\t\t}\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnSettings\n\t\t * Purpose:  Get the settings for a particular table for extern. manipulation\n\t\t * Returns:  -\n\t\t * Inputs:   -\n\t\t */\n\t\tthis.fnSettings = function( nNode  )\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnVersionCheck\n\t\t * Notes:    The function is the same as the 'static' function provided in the ext variable\n\t\t */\n\t\tthis.fnVersionCheck = _oExt.fnVersionCheck;\n\t\t\n\t\t/*\n\t\t * Function: fnSort\n\t\t * Purpose:  Sort the table by a particular row\n\t\t * Returns:  -\n\t\t * Inputs:   int:iCol - the data index to sort on. Note that this will\n\t\t *   not match the 'display index' if you have hidden data entries\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\toSettings.aaSorting = aaSort;\n\t\t\t_fnSort( oSettings );\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnSortListener\n\t\t * Purpose:  Attach a sort listener to an element for a given column\n\t\t * Returns:  -\n\t\t * Inputs:   node:nNode - the element to attach the sort listener to\n\t\t *           int:iColumn - the column that a click on this node will sort on\n\t\t *           function:fnCallback - callback function when sort is run - optional\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\t_fnSortAttachListener( _fnSettingsFromNode( this[_oExt.iApiIndex] ), nNode, iColumn,\n\t\t\t \tfnCallback );\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnAddData\n\t\t * Purpose:  Add new row(s) into the table\n\t\t * Returns:  array int: array of indexes (aoData) which have been added (zero length on error)\n\t\t * Inputs:   array:mData - the data to be added. The length must match\n\t\t *               the original data from the DOM\n\t\t *             or\n\t\t *             array array:mData - 2D array of data to be added\n\t\t *           bool:bRedraw - redraw the table or not - default true\n\t\t * Notes:    Warning - the refilter here will cause the table to redraw\n\t\t *             starting at zero\n\t\t * Notes:    Thanks to Yekimov Denis for contributing the basis for this function!\n\t\t */\n\t\tthis.fnAddData = function( mData, bRedraw )\n\t\t{\n\t\t\tif ( mData.length === 0 )\n\t\t\t{\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\t\n\t\t\tvar aiReturn = [];\n\t\t\tvar iTest;\n\t\t\t\n\t\t\t/* Find settings from table node */\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tif ( typeof mData[0] == \"object\" )\n\t\t\t{\n\t\t\t\tfor ( var i=0 ; i<mData.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\tiTest = _fnAddData( oSettings, mData[i] );\n\t\t\t\t\tif ( iTest == -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn aiReturn;\n\t\t\t\t\t}\n\t\t\t\t\taiReturn.push( iTest );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tiTest = _fnAddData( oSettings, mData );\n\t\t\t\tif ( iTest == -1 )\n\t\t\t\t{\n\t\t\t\t\treturn aiReturn;\n\t\t\t\t}\n\t\t\t\taiReturn.push( iTest );\n\t\t\t}\n\t\t\t\n\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\tif ( typeof bRedraw == 'undefined' || bRedraw )\n\t\t\t{\n\t\t\t\t_fnReDraw( oSettings );\n\t\t\t}\n\t\t\treturn aiReturn;\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnDeleteRow\n\t\t * Purpose:  Remove a row for the table\n\t\t * Returns:  array:aReturn - the row that was deleted\n\t\t * Inputs:   mixed:mTarget - \n\t\t *             int: - index of aoData to be deleted, or\n\t\t *             node(TR): - TR element you want to delete\n\t\t *           function:fnCallBack - callback function - default null\n\t\t *           bool:bRedraw - redraw the table or not - default true\n\t\t */\n\t\tthis.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )\n\t\t{\n\t\t\t/* Find settings from table node */\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\tvar i, iAODataIndex;\n\t\t\t\n\t\t\tiAODataIndex = (typeof mTarget == 'object') ? \n\t\t\t\t_fnNodeToDataIndex(oSettings, mTarget) : mTarget;\n\t\t\t\n\t\t\t/* Return the data array from this row */\n\t\t\tvar oData = oSettings.aoData.splice( iAODataIndex, 1 );\n\t\t\t\n\t\t\t/* Remove the target row from the search array */\n\t\t\tvar iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );\n\t\t\toSettings.asDataSearch.splice( iDisplayIndex, 1 );\n\t\t\t\n\t\t\t/* Delete from the display arrays */\n\t\t\t_fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );\n\t\t\t_fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );\n\t\t\t\n\t\t\t/* If there is a user callback function - call it */\n\t\t\tif ( typeof fnCallBack == \"function\" )\n\t\t\t{\n\t\t\t\tfnCallBack.call( this, oSettings, oData );\n\t\t\t}\n\t\t\t\n\t\t\t/* Check for an 'overflow' they case for dislaying the table */\n\t\t\tif ( oSettings._iDisplayStart >= oSettings.aiDisplay.length )\n\t\t\t{\n\t\t\t\toSettings._iDisplayStart -= oSettings._iDisplayLength;\n\t\t\t\tif ( oSettings._iDisplayStart < 0 )\n\t\t\t\t{\n\t\t\t\t\toSettings._iDisplayStart = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif ( typeof bRedraw == 'undefined' || bRedraw )\n\t\t\t{\n\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t_fnDraw( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\treturn oData;\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnClearTable\n\t\t * Purpose:  Quickly and simply clear a table\n\t\t * Returns:  -\n\t\t * Inputs:   bool:bRedraw - redraw the table or not - default true\n\t\t * Notes:    Thanks to Yekimov Denis for contributing the basis for this function!\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\t/* Find settings from table node */\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\t_fnClearTable( oSettings );\n\t\t\t\n\t\t\tif ( typeof bRedraw == 'undefined' || bRedraw )\n\t\t\t{\n\t\t\t\t_fnDraw( oSettings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnOpen\n\t\t * Purpose:  Open a display row (append a row after the row in question)\n\t\t * Returns:  node:nNewRow - the row opened\n\t\t * Inputs:   node:nTr - the table row to 'open'\n\t\t *           string:sHtml - the HTML to put into the row\n\t\t *           string:sClass - class to give the new TD cell\n\t\t */\n\t\tthis.fnOpen = function( nTr, sHtml, sClass )\n\t\t{\n\t\t\t/* Find settings from table node */\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\t\n\t\t\t/* the old open one if there is one */\n\t\t\tthis.fnClose( nTr );\n\t\t\t\n\t\t\tvar nNewRow = document.createElement(\"tr\");\n\t\t\tvar nNewCell = document.createElement(\"td\");\n\t\t\tnNewRow.appendChild( nNewCell );\n\t\t\tnNewCell.className = sClass;\n\t\t\tnNewCell.colSpan = _fnVisbleColumns( oSettings );\n\t\t\tnNewCell.innerHTML = sHtml;\n\t\t\t\n\t\t\t/* If the nTr isn't on the page at the moment - then we don't insert at the moment */\n\t\t\tvar nTrs = $('tr', oSettings.nTBody);\n\t\t\tif ( $.inArray(nTr, nTrs) != -1 )\n\t\t\t{\n\t\t\t\t$(nNewRow).insertAfter(nTr);\n\t\t\t}\n\t\t\t\n\t\t\toSettings.aoOpenRows.push( {\n\t\t\t\t\"nTr\": nNewRow,\n\t\t\t\t\"nParent\": nTr\n\t\t\t} );\n\t\t\t\n\t\t\treturn nNewRow;\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnClose\n\t\t * Purpose:  Close a display row\n\t\t * Returns:  int: 0 (success) or 1 (failed)\n\t\t * Inputs:   node:nTr - the table row to 'close'\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\t/* Find settings from table node */\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\t\n\t\t\tfor ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aoOpenRows[i].nParent == nTr )\n\t\t\t\t{\n\t\t\t\t\tvar nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;\n\t\t\t\t\tif ( nTrParent )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Remove it if it is currently on display */\n\t\t\t\t\t\tnTrParent.removeChild( oSettings.aoOpenRows[i].nTr );\n\t\t\t\t\t}\n\t\t\t\t\toSettings.aoOpenRows.splice( i, 1 );\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 1;\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnGetData\n\t\t * Purpose:  Return an array with the data which is used to make up the table\n\t\t * Returns:  array array string: 2d data array ([row][column]) or array string: 1d data array\n\t\t *           or\n\t\t *           array string (if iRow specified)\n\t\t * Inputs:   mixed:mRow - optional - if not present, then the full 2D array for the table \n\t\t *             if given then:\n\t\t *               int: - return 1D array for aoData entry of this index\n\t\t *               node(TR): - return 1D array for this TR element\n\t\t * Inputs:   int:iRow - optional - if present then the array returned will be the data for\n\t\t *             the row with the index 'iRow'\n\t\t */\n\t\tthis.fnGetData = function( mRow )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\t\n\t\t\tif ( typeof mRow != 'undefined' )\n\t\t\t{\n\t\t\t\tvar iRow = (typeof mRow == 'object') ? \n\t\t\t\t\t_fnNodeToDataIndex(oSettings, mRow) : mRow;\n\t\t\t\treturn oSettings.aoData[iRow]._aData;\n\t\t\t}\n\t\t\treturn _fnGetDataMaster( oSettings );\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnGetNodes\n\t\t * Purpose:  Return an array with the TR nodes used for drawing the table\n\t\t * Returns:  array node: TR elements\n\t\t *           or\n\t\t *           node (if iRow specified)\n\t\t * Inputs:   int:iRow - optional - if present then the array returned will be the node for\n\t\t *             the row with the index 'iRow'\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\t\n\t\t\tif ( typeof iRow != 'undefined' )\n\t\t\t{\n\t\t\t\treturn oSettings.aoData[iRow].nTr;\n\t\t\t}\n\t\t\treturn _fnGetTrNodes( oSettings );\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnGetPosition\n\t\t * Purpose:  Get the array indexes of a particular cell from it's DOM element\n\t\t * Returns:  int: - row index, or array[ int, int, int ]: - row index, column index (visible)\n\t\t *             and column index including hidden columns\n\t\t * Inputs:   node:nNode - this can either be a TR or a TD in the table, the return is\n\t\t *             dependent on this input\n\t\t */\n\t\tthis.fnGetPosition = function( nNode )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\tvar i;\n\t\t\t\n\t\t\tif ( nNode.nodeName.toUpperCase() == \"TR\" )\n\t\t\t{\n\t\t\t\treturn _fnNodeToDataIndex(oSettings, nNode);\n\t\t\t}\n\t\t\telse if ( nNode.nodeName.toUpperCase() == \"TD\" )\n\t\t\t{\n\t\t\t\tvar iDataIndex = _fnNodeToDataIndex(oSettings, nNode.parentNode);\n\t\t\t\tvar iCorrector = 0;\n\t\t\t\tfor ( var j=0 ; j<oSettings.aoColumns.length ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( oSettings.aoColumns[j].bVisible )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( oSettings.aoData[iDataIndex].nTr.getElementsByTagName('td')[j-iCorrector] == nNode )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn [ iDataIndex, j-iCorrector, j ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tiCorrector++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnUpdate\n\t\t * Purpose:  Update a table cell or row\n\t\t * Returns:  int: 0 okay, 1 error\n\t\t * Inputs:   array string 'or' string:mData - data to update the cell/row with\n\t\t *           mixed:mRow - \n\t\t *             int: - index of aoData to be updated, or\n\t\t *             node(TR): - TR element you want to update\n\t\t *           int:iColumn - the column to update - optional (not used of mData is 2D)\n\t\t *           bool:bRedraw - redraw the table or not - default true\n\t\t *           bool:bAction - perform predraw actions or not (you will want this as 'true' if\n\t\t *             you have bRedraw as true) - default true\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\tvar iVisibleColumn;\n\t\t\tvar sDisplay;\n\t\t\tvar iRow = (typeof mRow == 'object') ? \n\t\t\t\t_fnNodeToDataIndex(oSettings, mRow) : mRow;\n\t\t\t\n\t\t\tif ( typeof mData != 'object' )\n\t\t\t{\n\t\t\t\tsDisplay = mData;\n\t\t\t\toSettings.aoData[iRow]._aData[iColumn] = sDisplay;\n\t\t\t\t\n\t\t\t\tif ( oSettings.aoColumns[iColumn].fnRender !== null )\n\t\t\t\t{\n\t\t\t\t\tsDisplay = oSettings.aoColumns[iColumn].fnRender( {\n\t\t\t\t\t\t\"iDataRow\": iRow,\n\t\t\t\t\t\t\"iDataColumn\": iColumn,\n\t\t\t\t\t\t\"aData\": oSettings.aoData[iRow]._aData,\n\t\t\t\t\t\t\"oSettings\": oSettings\n\t\t\t\t\t} );\n\t\t\t\t\t\n\t\t\t\t\tif ( oSettings.aoColumns[iColumn].bUseRendered )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aoData[iRow]._aData[iColumn] = sDisplay;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tiVisibleColumn = _fnColumnIndexToVisible( oSettings, iColumn );\n\t\t\t\tif ( iVisibleColumn !== null )\n\t\t\t\t{\n\t\t\t\t\toSettings.aoData[iRow].nTr.getElementsByTagName('td')[iVisibleColumn].innerHTML = \n\t\t\t\t\t\tsDisplay;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ( mData.length != oSettings.aoColumns.length )\n\t\t\t\t{\n\t\t\t\t\t_fnLog( oSettings, 0, 'An array passed to fnUpdate must have the same number of '+\n\t\t\t\t\t\t'columns as the table in question - in this case '+oSettings.aoColumns.length );\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor ( var i=0 ; i<mData.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\tsDisplay = mData[i];\n\t\t\t\t\toSettings.aoData[iRow]._aData[i] = sDisplay;\n\t\t\t\t\t\n\t\t\t\t\tif ( oSettings.aoColumns[i].fnRender !== null )\n\t\t\t\t\t{\n\t\t\t\t\t\tsDisplay = oSettings.aoColumns[i].fnRender( {\n\t\t\t\t\t\t\t\"iDataRow\": iRow,\n\t\t\t\t\t\t\t\"iDataColumn\": i,\n\t\t\t\t\t\t\t\"aData\": oSettings.aoData[iRow]._aData,\n\t\t\t\t\t\t\t\"oSettings\": oSettings\n\t\t\t\t\t\t} );\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ( oSettings.aoColumns[i].bUseRendered )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toSettings.aoData[iRow]._aData[i] = sDisplay;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tiVisibleColumn = _fnColumnIndexToVisible( oSettings, i );\n\t\t\t\t\tif ( iVisibleColumn !== null )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aoData[iRow].nTr.getElementsByTagName('td')[iVisibleColumn].innerHTML = \n\t\t\t\t\t\t\tsDisplay;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Modify the search index for this row (strictly this is likely not needed, since fnReDraw\n\t\t\t * will rebuild the search array - however, the redraw might be disabled by the user)\n\t\t\t */\n\t\t\tvar iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );\n\t\t\toSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow( oSettings, \n\t\t\t\toSettings.aoData[iRow]._aData );\n\t\t\t\n\t\t\t/* Perform pre-draw actions */\n\t\t\tif ( typeof bAction == 'undefined' || bAction )\n\t\t\t{\n\t\t\t\t_fnAjustColumnSizing( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* Redraw the table */\n\t\t\tif ( typeof bRedraw == 'undefined' || bRedraw )\n\t\t\t{\n\t\t\t\t_fnReDraw( oSettings );\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/*\n\t\t * Function: fnShowColoumn\n\t\t * Purpose:  Show a particular column\n\t\t * Returns:  -\n\t\t * Inputs:   int:iCol - the column whose display should be changed\n\t\t *           bool:bShow - show (true) or hide (false) the column\n\t\t *           bool:bRedraw - redraw the table or not - default true\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\tvar i, iLen;\n\t\t\tvar iColumns = oSettings.aoColumns.length;\n\t\t\tvar nTd, anTds;\n\t\t\t\n\t\t\t/* No point in doing anything if we are requesting what is already true */\n\t\t\tif ( oSettings.aoColumns[iCol].bVisible == bShow )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar nTrHead = $('>tr', oSettings.nTHead)[0];\n\t\t\tvar nTrFoot = $('>tr', oSettings.nTFoot)[0];\n\t\t\tvar anTheadTh = [];\n\t\t\tvar anTfootTh = [];\n\t\t\tfor ( i=0 ; i<iColumns ; i++ )\n\t\t\t{\n\t\t\t\tanTheadTh.push( oSettings.aoColumns[i].nTh );\n\t\t\t\tanTfootTh.push( oSettings.aoColumns[i].nTf );\n\t\t\t}\n\t\t\t\n\t\t\t/* Show the column */\n\t\t\tif ( bShow )\n\t\t\t{\n\t\t\t\tvar iInsert = 0;\n\t\t\t\tfor ( i=0 ; i<iCol ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( oSettings.aoColumns[i].bVisible )\n\t\t\t\t\t{\n\t\t\t\t\t\tiInsert++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Need to decide if we should use appendChild or insertBefore */\n\t\t\t\tif ( iInsert >= _fnVisbleColumns( oSettings ) )\n\t\t\t\t{\n\t\t\t\t\tnTrHead.appendChild( anTheadTh[iCol] );\n\t\t\t\t\tif ( nTrFoot )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTrFoot.appendChild( anTfootTh[iCol] );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTd = oSettings.aoData[i]._anHidden[iCol];\n\t\t\t\t\t\toSettings.aoData[i].nTr.appendChild( nTd );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t/* Which coloumn should we be inserting before? */\n\t\t\t\t\tvar iBefore;\n\t\t\t\t\tfor ( i=iCol ; i<iColumns ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tiBefore = _fnColumnIndexToVisible( oSettings, i );\n\t\t\t\t\t\tif ( iBefore !== null )\n\t\t\t\t\t\t{\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\t\n\t\t\t\t\tnTrHead.insertBefore( anTheadTh[iCol], nTrHead.getElementsByTagName('th')[iBefore] );\n\t\t\t\t\tif ( nTrFoot )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTrFoot.insertBefore( anTfootTh[iCol], nTrFoot.getElementsByTagName('th')[iBefore] );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tanTds = _fnGetTdNodes( oSettings );\n\t\t\t\t\tfor ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTd = oSettings.aoData[i]._anHidden[iCol];\n\t\t\t\t\t\toSettings.aoData[i].nTr.insertBefore( nTd, $('>td:eq('+iBefore+')', \n\t\t\t\t\t\t\toSettings.aoData[i].nTr)[0] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\toSettings.aoColumns[iCol].bVisible = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Remove a column from display */\n\t\t\t\tnTrHead.removeChild( anTheadTh[iCol] );\n\t\t\t\tif ( nTrFoot )\n\t\t\t\t{\n\t\t\t\t\tnTrFoot.removeChild( anTfootTh[iCol] );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tanTds = _fnGetTdNodes( oSettings );\n\t\t\t\tfor ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tnTd = anTds[ ( i*oSettings.aoColumns.length) + (iCol*1) ];\n\t\t\t\t\toSettings.aoData[i]._anHidden[iCol] = nTd;\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\toSettings.aoColumns[iCol].bVisible = false;\n\t\t\t}\n\t\t\t\n\t\t\t/* If there are any 'open' rows, then we need to alter the colspan for this col change */\n\t\t\tfor ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* Do a redraw incase anything depending on the table columns needs it \n\t\t\t * (built-in: scrolling) \n\t\t\t */\n\t\t\tif ( typeof bRedraw == 'undefined' || bRedraw )\n\t\t\t{\n\t\t\t\t_fnAjustColumnSizing( oSettings );\n\t\t\t\t_fnDraw( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t_fnSaveState( oSettings );\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnPageChange\n\t\t * Purpose:  Change the pagination\n\t\t * Returns:  -\n\t\t * Inputs:   string:sAction - paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *           bool:bRedraw - redraw the table or not - optional - default true\n\t\t */\n\t\tthis.fnPageChange = function ( sAction, bRedraw )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\t_fnPageChange( oSettings, sAction );\n\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\n\t\t\tif ( typeof bRedraw == 'undefined' || bRedraw )\n\t\t\t{\n\t\t\t\t_fnDraw( oSettings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: fnDestroy\n\t\t * Purpose:  Destructor for the DataTable\n\t\t * Returns:  -\n\t\t * Inputs:   -\n\t\t */\n\t\tthis.fnDestroy = function ( )\n\t\t{\n\t\t\tvar oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );\n\t\t\tvar nOrig = oSettings.nTableWrapper.parentNode;\n\t\t\tvar nBody = oSettings.nTBody;\n\t\t\tvar i, iLen;\n\t\t\t\n\t\t\t/* Flag to note that the table is currently being destoryed - no action should be taken */\n\t\t\toSettings.bDestroying = true;\n\t\t\t\n\t\t\t/* Restore hidden columns */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aoColumns[i].bVisible === false )\n\t\t\t\t{\n\t\t\t\t\tthis.fnSetColumnVis( i, true );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* If there is an 'empty' indicator row, remove it */\n\t\t\t$('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();\n\t\t\t\n\t\t\t/* When scrolling we had to break the table up - restore it */\n\t\t\tif ( oSettings.nTable != oSettings.nTHead.parentNode )\n\t\t\t{\n\t\t\t\t$('>thead', oSettings.nTable).remove();\n\t\t\t\toSettings.nTable.appendChild( oSettings.nTHead );\n\t\t\t}\n\t\t\t\n\t\t\tif ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )\n\t\t\t{\n\t\t\t\t$('>tfoot', oSettings.nTable).remove();\n\t\t\t\toSettings.nTable.appendChild( oSettings.nTFoot );\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove the DataTables generated nodes, events and classes */\n\t\t\toSettings.nTable.parentNode.removeChild( oSettings.nTable );\n\t\t\t$(oSettings.nTableWrapper).remove();\n\t\t\t\n\t\t\toSettings.aaSorting = [];\n\t\t\toSettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t$(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripClasses.join(' ') );\n\t\t\t\n\t\t\tif ( !oSettings.bJUI )\n\t\t\t{\n\t\t\t\t$('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,\n\t\t\t\t\t_oExt.oStdClasses.sSortableAsc,\n\t\t\t\t\t_oExt.oStdClasses.sSortableDesc,\n\t\t\t\t\t_oExt.oStdClasses.sSortableNone ].join(' ')\n\t\t\t\t);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,\n\t\t\t\t\t_oExt.oJUIClasses.sSortableAsc,\n\t\t\t\t\t_oExt.oJUIClasses.sSortableDesc,\n\t\t\t\t\t_oExt.oJUIClasses.sSortableNone ].join(' ')\n\t\t\t\t);\n\t\t\t\t$('th span', oSettings.nTHead).remove();\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the TR elements back into the table in their original order */\n\t\t\tnOrig.appendChild( oSettings.nTable );\n\t\t\tfor ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tnBody.appendChild( oSettings.aoData[i].nTr );\n\t\t\t}\n\t\t\t\n\t\t\t/* Restore the width of the original table */\n\t\t\toSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);\n\t\t\t\n\t\t\t/* If the were originally odd/even type classes - then we add them back here. Note\n\t\t\t * this is not fool proof (for example if not all rows as odd/even classes - but \n\t\t\t * it's a good effort without getting carried away\n\t\t\t */\n\t\t\t$('>tr:even', nBody).addClass( oSettings.asDestoryStrips[0] );\n\t\t\t$('>tr:odd', nBody).addClass( oSettings.asDestoryStrips[1] );\n\t\t\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tfor ( i=0, iLen=_aoSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tif ( _aoSettings[i] == oSettings )\n\t\t\t\t{\n\t\t\t\t\t_aoSettings.splice( i, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* End it all */\n\t\t\toSettings = null;\n\t\t};\n\t\t\n\t\t/*\n\t\t * Function: _fnAjustColumnSizing\n\t\t * Purpose:  Update tale sizing based on content. This would most likely be used for scrolling\n\t\t *   and will typically need a redraw after it.\n\t\t * Returns:  -\n\t\t * Inputs:   bool:bRedraw - redraw the table or not, you will typically want to - default true\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\t_fnAjustColumnSizing( _fnSettingsFromNode( this[_oExt.iApiIndex] ) );\n\t\t\t\n\t\t\tif ( typeof bRedraw == 'undefined' || bRedraw )\n\t\t\t{\n\t\t\t\tthis.fnDraw( false );\n\t\t\t}\n\t\t};\n\t\t\n\t\t/*\n\t\t * Plugin API functions\n\t\t * \n\t\t * This call will add the functions which are defined in _oExt.oApi to the\n\t\t * DataTables object, providing a rather nice way to allow plug-in API functions. Note that\n\t\t * this is done here, so that API function can actually override the built in API functions if\n\t\t * required for a particular purpose.\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnExternApiFunc\n\t\t * Purpose:  Create a wrapper function for exporting an internal func to an external API func\n\t\t * Returns:  function: - wrapped function\n\t\t * Inputs:   string:sFunc - API function name\n\t\t */\n\t\tfunction _fnExternApiFunc (sFunc)\n\t\t{\n\t\t\treturn function() {\n\t\t\t\t\tvar aArgs = [_fnSettingsFromNode(this[_oExt.iApiIndex])].concat( \n\t\t\t\t\t\tArray.prototype.slice.call(arguments) );\n\t\t\t\t\treturn _oExt.oApi[sFunc].apply( this, aArgs );\n\t\t\t\t};\n\t\t}\n\t\t\n\t\tfor ( var sFunc in _oExt.oApi )\n\t\t{\n\t\t\tif ( sFunc )\n\t\t\t{\n\t\t\t\t/*\n\t\t\t\t * Function: anon\n\t\t\t\t * Purpose:  Wrap the plug-in API functions in order to provide the settings as 1st arg \n\t\t\t\t *   and execute in this scope\n\t\t\t\t * Returns:  -\n\t\t\t\t * Inputs:   -\n\t\t\t\t */\n\t\t\t\tthis[sFunc] = _fnExternApiFunc(sFunc);\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Local functions\n\t\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Initalisation\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnInitalise\n\t\t * Purpose:  Draw the table for the first time, adding all required features\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnInitalise ( oSettings )\n\t\t{\n\t\t\tvar i, iLen;\n\t\t\t\n\t\t\t/* Ensure that the table data is fully initialised */\n\t\t\tif ( oSettings.bInitialised === false )\n\t\t\t{\n\t\t\t\tsetTimeout( function(){ _fnInitalise( oSettings ); }, 200 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Show the display HTML options */\n\t\t\t_fnAddOptionsHtml( oSettings );\n\t\t\t\n\t\t\t/* Draw the headers for the table */\n\t\t\t_fnDrawHead( oSettings );\n\t\t\t\n\t\t\t/* Okay to show that something is going on now */\n\t\t\t_fnProcessingDisplay( oSettings, true );\n\t\t\t\n\t\t\t/* Calculate sizes for columns */\n\t\t\tif ( oSettings.oFeatures.bAutoWidth )\n\t\t\t{\n\t\t\t\t_fnCalculateColumnWidths( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aoColumns[i].sWidth !== null )\n\t\t\t\t{\n\t\t\t\t\toSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* If there is default sorting required - let's do it. The sort function\n\t\t\t * will do the drawing for us. Otherwise we draw the table\n\t\t\t */\n\t\t\tif ( oSettings.oFeatures.bSort )\n\t\t\t{\n\t\t\t\t_fnSort( oSettings );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t_fnDraw( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* if there is an ajax source */\n\t\t\tif ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )\n\t\t\t{\n\t\t\t\toSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, [], function(json) {\n\t\t\t\t\t/* Got the data - add it to the table */\n\t\t\t\t\tfor ( i=0 ; i<json.aaData.length ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnAddData( oSettings, json.aaData[i] );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t/* Reset the init display for cookie saving. We've already done a filter, and\n\t\t\t\t\t * therefore cleared it before. So we need to make it appear 'fresh'\n\t\t\t\t\t */\n\t\t\t\t\toSettings.iInitDisplayStart = oSettings._iDisplayStart;\n\t\t\t\t\t\n\t\t\t\t\tif ( oSettings.oFeatures.bSort )\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnSort( oSettings );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t\t\t_fnDraw( oSettings );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t\t\t\n\t\t\t\t\t/* Run the init callback if there is one - done here for ajax source for json obj */\n\t\t\t\t\tif ( typeof oSettings.fnInitComplete == 'function' )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.fnInitComplete.call( oSettings.oInstance, oSettings, json );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif ( !oSettings.oFeatures.bServerSide )\n\t\t\t{\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnLanguageProcess\n\t\t * Purpose:  Copy language variables from remote object to a local one\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           object:oLanguage - Language information\n\t\t *           bool:bInit - init once complete\n\t\t */\n\t\tfunction _fnLanguageProcess( oSettings, oLanguage, bInit )\n\t\t{\n\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sProcessing' );\n\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sLengthMenu' );\n\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sEmptyTable' );\n\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sZeroRecords' );\n\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sInfo' );\n\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sInfoEmpty' );\n\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sInfoFiltered' );\n\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sInfoPostFix' );\n\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sSearch' );\n\t\t\t\n\t\t\tif ( typeof oLanguage.oPaginate != 'undefined' )\n\t\t\t{\n\t\t\t\t_fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sFirst' );\n\t\t\t\t_fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sPrevious' );\n\t\t\t\t_fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sNext' );\n\t\t\t\t_fnMap( oSettings.oLanguage.oPaginate, oLanguage.oPaginate, 'sLast' );\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t\t * sZeroRecords - assuming that is given.\n\t\t\t */\n\t\t\tif ( typeof oLanguage.sEmptyTable == 'undefined' && \n\t\t\t     typeof oLanguage.sZeroRecords != 'undefined' )\n\t\t\t{\n\t\t\t\t_fnMap( oSettings.oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );\n\t\t\t}\n\t\t\t\n\t\t\tif ( bInit )\n\t\t\t{\n\t\t\t\t_fnInitalise( oSettings );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnAddColumn\n\t\t * Purpose:  Add a column to the list used for the table with default values\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           node:nTh - the th element for this column\n\t\t */\n\t\tfunction _fnAddColumn( oSettings, nTh )\n\t\t{\n\t\t\toSettings.aoColumns[ oSettings.aoColumns.length++ ] = {\n\t\t\t\t\"sType\": null,\n\t\t\t\t\"_bAutoType\": true,\n\t\t\t\t\"bVisible\": true,\n\t\t\t\t\"bSearchable\": true,\n\t\t\t\t\"bSortable\": true,\n\t\t\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\t\t\t\"sSortingClass\": oSettings.oClasses.sSortable,\n\t\t\t\t\"sSortingClassJUI\": oSettings.oClasses.sSortJUI,\n\t\t\t\t\"sTitle\": nTh ? nTh.innerHTML : '',\n\t\t\t\t\"sName\": '',\n\t\t\t\t\"sWidth\": null,\n\t\t\t\t\"sWidthOrig\": null,\n\t\t\t\t\"sClass\": null,\n\t\t\t\t\"fnRender\": null,\n\t\t\t\t\"bUseRendered\": true,\n\t\t\t\t\"iDataSort\": oSettings.aoColumns.length-1,\n\t\t\t\t\"sSortDataType\": 'std',\n\t\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\t\"nTf\": null\n\t\t\t};\n\t\t\t\n\t\t\tvar iCol = oSettings.aoColumns.length-1;\n\t\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\t\t\n\t\t\t/* Add a column specific filter */\n\t\t\tif ( typeof oSettings.aoPreSearchCols[ iCol ] == 'undefined' ||\n\t\t\t     oSettings.aoPreSearchCols[ iCol ] === null )\n\t\t\t{\n\t\t\t\toSettings.aoPreSearchCols[ iCol ] = {\n\t\t\t\t\t\"sSearch\": \"\",\n\t\t\t\t\t\"bRegex\": false,\n\t\t\t\t\t\"bSmart\": true\n\t\t\t\t};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Don't require that the user must specify bRegex and / or bSmart */\n\t\t\t\tif ( typeof oSettings.aoPreSearchCols[ iCol ].bRegex == 'undefined' )\n\t\t\t\t{\n\t\t\t\t\toSettings.aoPreSearchCols[ iCol ].bRegex = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( typeof oSettings.aoPreSearchCols[ iCol ].bSmart == 'undefined' )\n\t\t\t\t{\n\t\t\t\t\toSettings.aoPreSearchCols[ iCol ].bSmart = true;\n\t\t\t\t}\n\t\t\t} \n\t\t\t\n\t\t\t/* Use the column options function to initialise classes etc */\n\t\t\t_fnColumnOptions( oSettings, iCol, null );\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnColumnOptions\n\t\t * Purpose:  Apply options for a column\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           int:iCol - column index to consider\n\t\t *           object:oOptions - object with sType, bVisible and bSearchable\n\t\t */\n\t\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t\t{\n\t\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\t\t\n\t\t\t/* User specified column options */\n\t\t\tif ( typeof oOptions != 'undefined' && oOptions !== null )\n\t\t\t{\n\t\t\t\tif ( typeof oOptions.sType != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\toCol.sType = oOptions.sType;\n\t\t\t\t\toCol._bAutoType = false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t_fnMap( oCol, oOptions, \"bVisible\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"bSearchable\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"bSortable\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"sTitle\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"sName\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"sWidth\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"sClass\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"fnRender\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"bUseRendered\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"iDataSort\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"asSorting\" );\n\t\t\t\t_fnMap( oCol, oOptions, \"sSortDataType\" );\n\t\t\t}\n\t\t\t\n\t\t\t/* Feature sorting overrides column specific when off */\n\t\t\tif ( !oSettings.oFeatures.bSort )\n\t\t\t{\n\t\t\t\toCol.bSortable = false;\n\t\t\t}\n\t\t\t\n\t\t\t/* Check that the class assignment is correct for sorting */\n\t\t\tif ( !oCol.bSortable ||\n\t\t\t\t\t ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )\n\t\t\t{\n\t\t\t\toCol.sSortingClass = oSettings.oClasses.sSortableNone;\n\t\t\t\toCol.sSortingClassJUI = \"\";\n\t\t\t}\n\t\t\telse if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )\n\t\t\t{\n\t\t\t\toCol.sSortingClass = oSettings.oClasses.sSortableAsc;\n\t\t\t\toCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;\n\t\t\t}\n\t\t\telse if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )\n\t\t\t{\n\t\t\t\toCol.sSortingClass = oSettings.oClasses.sSortableDesc;\n\t\t\t\toCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnAddData\n\t\t * Purpose:  Add a data array to the table, creating DOM node etc\n\t\t * Returns:  int: - >=0 if successful (index of new aoData entry), -1 if failed\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           array:aData - data array to be added\n\t\t * Notes:    There are two basic methods for DataTables to get data to display - a JS array\n\t\t *   (which is dealt with by this function), and the DOM, which has it's own optimised\n\t\t *   function (_fnGatherData). Be careful to make the same changes here as there and vice-versa\n\t\t */\n\t\tfunction _fnAddData ( oSettings, aDataSupplied )\n\t\t{\n\t\t\t/* Sanity check the length of the new array */\n\t\t\tif ( aDataSupplied.length != oSettings.aoColumns.length &&\n\t\t\t\toSettings.iDrawError != oSettings.iDraw )\n\t\t\t{\n\t\t\t\t_fnLog( oSettings, 0, \"Added data (size \"+aDataSupplied.length+\") does not match known \"+\n\t\t\t\t\t\"number of columns (\"+oSettings.aoColumns.length+\")\" );\n\t\t\t\toSettings.iDrawError = oSettings.iDraw;\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t/* Create the object for storing information about this new row */\n\t\t\tvar aData = aDataSupplied.slice();\n\t\t\tvar iThisIndex = oSettings.aoData.length;\n\t\t\toSettings.aoData.push( {\n\t\t\t\t\"nTr\": document.createElement('tr'),\n\t\t\t\t\"_iId\": oSettings.iNextId++,\n\t\t\t\t\"_aData\": aData,\n\t\t\t\t\"_anHidden\": [],\n\t\t\t\t\"_sRowStripe\": ''\n\t\t\t} );\n\t\t\t\n\t\t\t/* Create the cells */\n\t\t\tvar nTd, sThisType;\n\t\t\tfor ( var i=0 ; i<aData.length ; i++ )\n\t\t\t{\n\t\t\t\tnTd = document.createElement('td');\n\t\t\t\t\n\t\t\t\t/* Allow null data (from a data array) - simply deal with it as a blank string */\n\t\t\t\tif ( aData[i] === null )\n\t\t\t\t{\n\t\t\t\t\taData[i] = '';\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( typeof oSettings.aoColumns[i].fnRender == 'function' )\n\t\t\t\t{\n\t\t\t\t\tvar sRendered = oSettings.aoColumns[i].fnRender( {\n\t\t\t\t\t\t\t\"iDataRow\": iThisIndex,\n\t\t\t\t\t\t\t\"iDataColumn\": i,\n\t\t\t\t\t\t\t\"aData\": aData,\n\t\t\t\t\t\t\t\"oSettings\": oSettings\n\t\t\t\t\t\t} );\n\t\t\t\t\tnTd.innerHTML = sRendered;\n\t\t\t\t\tif ( oSettings.aoColumns[i].bUseRendered )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Use the rendered data for filtering/sorting */\n\t\t\t\t\t\toSettings.aoData[iThisIndex]._aData[i] = sRendered;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnTd.innerHTML = aData[i];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Cast everything as a string - so we can treat everything equally when sorting */\n\t\t\t\tif ( typeof aData[i] != 'string' )\n\t\t\t\t{\n\t\t\t\t\taData[i] += \"\";\n\t\t\t\t}\n\t\t\t\taData[i] = $.trim(aData[i]);\n\t\t\t\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oSettings.aoColumns[i].sClass !== null )\n\t\t\t\t{\n\t\t\t\t\tnTd.className = oSettings.aoColumns[i].sClass;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* See if we should auto-detect the column type */\n\t\t\t\tif ( oSettings.aoColumns[i]._bAutoType && oSettings.aoColumns[i].sType != 'string' )\n\t\t\t\t{\n\t\t\t\t\t/* Attempt to auto detect the type - same as _fnGatherData() */\n\t\t\t\t\tsThisType = _fnDetectType( oSettings.aoData[iThisIndex]._aData[i] );\n\t\t\t\t\tif ( oSettings.aoColumns[i].sType === null )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aoColumns[i].sType = sThisType;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( oSettings.aoColumns[i].sType != sThisType )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* String is always the 'fallback' option */\n\t\t\t\t\t\toSettings.aoColumns[i].sType = 'string';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\tif ( oSettings.aoColumns[i].bVisible )\n\t\t\t\t{\n\t\t\t\t\toSettings.aoData[iThisIndex].nTr.appendChild( nTd );\n\t\t\t\t\toSettings.aoData[iThisIndex]._anHidden[i] = null;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\toSettings.aoData[iThisIndex]._anHidden[i] = nTd;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Add to the display array */\n\t\t\toSettings.aiDisplayMaster.push( iThisIndex );\n\t\t\treturn iThisIndex;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnGatherData\n\t\t * Purpose:  Read in the data from the target table from the DOM\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t * Notes:    This is a optimised version of _fnAddData (more or less) for reading information\n\t\t *   from the DOM. The basic actions must be identical in the two functions.\n\t\t */\n\t\tfunction _fnGatherData( oSettings )\n\t\t{\n\t\t\tvar iLoop, i, iLen, j, jLen, jInner,\n\t\t\t \tnTds, nTrs, nTd, aLocalData, iThisIndex,\n\t\t\t\tiRow, iRows, iColumn, iColumns;\n\t\t\t\n\t\t\t/*\n\t\t\t * Process by row first\n\t\t\t * Add the data object for the whole table - storing the tr node. Note - no point in getting\n\t\t\t * DOM based data if we are going to go and replace it with Ajax source data.\n\t\t\t */\n\t\t\tif ( oSettings.sAjaxSource === null )\n\t\t\t{\n\t\t\t\tnTrs = oSettings.nTBody.childNodes;\n\t\t\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( nTrs[i].nodeName.toUpperCase() == \"TR\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tiThisIndex = oSettings.aoData.length;\n\t\t\t\t\t\toSettings.aoData.push( {\n\t\t\t\t\t\t\t\"nTr\": nTrs[i],\n\t\t\t\t\t\t\t\"_iId\": oSettings.iNextId++,\n\t\t\t\t\t\t\t\"_aData\": [],\n\t\t\t\t\t\t\t\"_anHidden\": [],\n\t\t\t\t\t\t\t\"_sRowStripe\": ''\n\t\t\t\t\t\t} );\n\t\t\t\t\t\t\n\t\t\t\t\t\toSettings.aiDisplayMaster.push( iThisIndex );\n\t\t\t\t\t\t\n\t\t\t\t\t\taLocalData = oSettings.aoData[iThisIndex]._aData;\n\t\t\t\t\t\tnTds = nTrs[i].childNodes;\n\t\t\t\t\t\tjInner = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor ( j=0, jLen=nTds.length ; j<jLen ; j++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( nTds[j].nodeName.toUpperCase() == \"TD\" )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\taLocalData[jInner] = $.trim(nTds[j].innerHTML);\n\t\t\t\t\t\t\t\tjInner++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Gather in the TD elements of the Table - note that this is basically the same as\n\t\t\t * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet\n\t\t\t * setup!\n\t\t\t */\n\t\t\tnTrs = _fnGetTrNodes( oSettings );\n\t\t\tnTds = [];\n\t\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfor ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tnTd = nTrs[i].childNodes[j];\n\t\t\t\t\tif ( nTd.nodeName.toUpperCase() == \"TD\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTds.push( nTd );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( nTds.length != nTrs.length * oSettings.aoColumns.length )\n\t\t\t{\n\t\t\t\t_fnLog( oSettings, 1, \"Unexpected number of TD elements. Expected \"+\n\t\t\t\t\t(nTrs.length * oSettings.aoColumns.length)+\" and got \"+nTds.length+\". DataTables does \"+\n\t\t\t\t\t\"not support rowspan / colspan in the table body, and there must be one cell for each \"+\n\t\t\t\t\t\"row/column combination.\" );\n\t\t\t}\n\t\t\t\n\t\t\t/* Now process by column */\n\t\t\tfor ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )\n\t\t\t{\n\t\t\t\t/* Get the title of the column - unless there is a user set one */\n\t\t\t\tif ( oSettings.aoColumns[iColumn].sTitle === null )\n\t\t\t\t{\n\t\t\t\t\toSettings.aoColumns[iColumn].sTitle = oSettings.aoColumns[iColumn].nTh.innerHTML;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar\n\t\t\t\t\tbAutoType = oSettings.aoColumns[iColumn]._bAutoType,\n\t\t\t\t\tbRender = typeof oSettings.aoColumns[iColumn].fnRender == 'function',\n\t\t\t\t\tbClass = oSettings.aoColumns[iColumn].sClass !== null,\n\t\t\t\t\tbVisible = oSettings.aoColumns[iColumn].bVisible,\n\t\t\t\t\tnCell, sThisType, sRendered;\n\t\t\t\t\n\t\t\t\t/* A single loop to rule them all (and be more efficient) */\n\t\t\t\tif ( bAutoType || bRender || bClass || !bVisible )\n\t\t\t\t{\n\t\t\t\t\tfor ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tnCell = nTds[ (iRow*iColumns) + iColumn ];\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* Type detection */\n\t\t\t\t\t\tif ( bAutoType )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( oSettings.aoColumns[iColumn].sType != 'string' )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsThisType = _fnDetectType( oSettings.aoData[iRow]._aData[iColumn] );\n\t\t\t\t\t\t\t\tif ( oSettings.aoColumns[iColumn].sType === null )\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\toSettings.aoColumns[iColumn].sType = sThisType;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if ( oSettings.aoColumns[iColumn].sType != sThisType )\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t/* String is always the 'fallback' option */\n\t\t\t\t\t\t\t\t\toSettings.aoColumns[iColumn].sType = 'string';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* Rendering */\n\t\t\t\t\t\tif ( bRender )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsRendered = oSettings.aoColumns[iColumn].fnRender( {\n\t\t\t\t\t\t\t\t\t\"iDataRow\": iRow,\n\t\t\t\t\t\t\t\t\t\"iDataColumn\": iColumn,\n\t\t\t\t\t\t\t\t\t\"aData\": oSettings.aoData[iRow]._aData,\n\t\t\t\t\t\t\t\t\t\"oSettings\": oSettings\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\tnCell.innerHTML = sRendered;\n\t\t\t\t\t\t\tif ( oSettings.aoColumns[iColumn].bUseRendered )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t/* Use the rendered data for filtering/sorting */\n\t\t\t\t\t\t\t\toSettings.aoData[iRow]._aData[iColumn] = sRendered;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* Classes */\n\t\t\t\t\t\tif ( bClass )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnCell.className += ' '+oSettings.aoColumns[iColumn].sClass;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* Column visability */\n\t\t\t\t\t\tif ( !bVisible )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toSettings.aoData[iRow]._anHidden[iColumn] = nCell;\n\t\t\t\t\t\t\tnCell.parentNode.removeChild( nCell );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toSettings.aoData[iRow]._anHidden[iColumn] = null;\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\t\t\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Drawing functions\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnDrawHead\n\t\t * Purpose:  Create the HTML header for the table\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnDrawHead( oSettings )\n\t\t{\n\t\t\tvar i, nTh, iLen, j, jLen;\n\t\t\tvar iThs = oSettings.nTHead.getElementsByTagName('th').length;\n\t\t\tvar iCorrector = 0;\n\t\t\t\n\t\t\t/* If there is a header in place - then use it - otherwise it's going to get nuked... */\n\t\t\tif ( iThs !== 0 )\n\t\t\t{\n\t\t\t\t/* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */\n\t\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tnTh = oSettings.aoColumns[i].nTh;\n\t\t\t\t\t\n\t\t\t\t\tif ( oSettings.aoColumns[i].bVisible )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Set the title of the column if it is user defined (not what was auto detected) */\n\t\t\t\t\t\tif ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnTh.innerHTML = oSettings.aoColumns[i].sTitle;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnTh.parentNode.removeChild( nTh );\n\t\t\t\t\t\tiCorrector++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* We don't have a header in the DOM - so we are going to have to create one */\n\t\t\t\tvar nTr = document.createElement( \"tr\" );\n\t\t\t\t\n\t\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tnTh = oSettings.aoColumns[i].nTh;\n\t\t\t\t\tnTh.innerHTML = oSettings.aoColumns[i].sTitle;\n\t\t\t\t\t\n\t\t\t\t\tif ( oSettings.aoColumns[i].bVisible )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( oSettings.aoColumns[i].sClass !== null )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnTh.className = oSettings.aoColumns[i].sClass;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tnTr.appendChild( nTh );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t$(oSettings.nTHead).html( '' )[0].appendChild( nTr );\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the extra markup needed by jQuery UI's themes */\n\t\t\tif ( oSettings.bJUI )\n\t\t\t{\n\t\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tnTh = oSettings.aoColumns[i].nTh;\n\t\t\t\t\t\n\t\t\t\t\tvar nDiv = document.createElement('div');\n\t\t\t\t\tnDiv.className = oSettings.oClasses.sSortJUIWrapper;\n\t\t\t\t\t$(nTh).contents().appendTo(nDiv);\n\t\t\t\t\t\n\t\t\t\t\tnDiv.appendChild( document.createElement('span') );\n\t\t\t\t\tnTh.appendChild( nDiv );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Add sort listener */\n\t\t\tvar fnNoSelect = function (e) {\n\t\t\t\tthis.onselectstart = function() { return false; };\n\t\t\t\treturn false;\n\t\t\t};\n\t\t\t\n\t\t\tif ( oSettings.oFeatures.bSort )\n\t\t\t{\n\t\t\t\tfor ( i=0 ; i<oSettings.aoColumns.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( oSettings.aoColumns[i].bSortable !== false )\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* Take the brutal approach to cancelling text selection in header */\n\t\t\t\t\t\t$(oSettings.aoColumns[i].nTh).mousedown( fnNoSelect );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t$(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Cache the footer elements */\n\t\t\tif ( oSettings.nTFoot !== null )\n\t\t\t{\n\t\t\t\tiCorrector = 0;\n\t\t\t\tvar nTfs = oSettings.nTFoot.getElementsByTagName('th');\n\t\t\t\tfor ( i=0, iLen=nTfs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof oSettings.aoColumns[i] != 'undefined' )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aoColumns[i].nTf = nTfs[i-iCorrector];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ( oSettings.oClasses.sFooterTH !== \"\" )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toSettings.aoColumns[i].nTf.className += \" \"+oSettings.oClasses.sFooterTH;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ( !oSettings.aoColumns[i].bVisible )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnTfs[i-iCorrector].parentNode.removeChild( nTfs[i-iCorrector] );\n\t\t\t\t\t\t\tiCorrector++;\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\t\t\n\t\t/*\n\t\t * Function: _fnDraw\n\t\t * Purpose:  Insert the required TR nodes into the table for display\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnDraw( oSettings )\n\t\t{\n\t\t\tvar i, iLen;\n\t\t\tvar anRows = [];\n\t\t\tvar iRowCount = 0;\n\t\t\tvar bRowError = false;\n\t\t\tvar iStrips = oSettings.asStripClasses.length;\n\t\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\t\t\n\t\t\toSettings.bDrawing = true;\n\t\t\t\n\t\t\t/* Check and see if we have an initial draw position from state saving */\n\t\t\tif ( typeof oSettings.iInitDisplayStart != 'undefined' && oSettings.iInitDisplayStart != -1 )\n\t\t\t{\n\t\t\t\tif ( oSettings.oFeatures.bServerSide )\n\t\t\t\t{\n\t\t\t\t\toSettings._iDisplayStart = oSettings.iInitDisplayStart;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\toSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?\n\t\t\t\t\t\t0 : oSettings.iInitDisplayStart;\n\t\t\t\t}\n\t\t\t\toSettings.iInitDisplayStart = -1;\n\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If we are dealing with Ajax - do it here */\n\t\t\tif ( oSettings.oFeatures.bServerSide && \n\t\t\t     !_fnAjaxUpdate( oSettings ) )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if ( !oSettings.oFeatures.bServerSide )\n\t\t\t{\n\t\t\t\toSettings.iDraw++;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oSettings.aiDisplay.length !== 0 )\n\t\t\t{\n\t\t\t\tvar iStart = oSettings._iDisplayStart;\n\t\t\t\tvar iEnd = oSettings._iDisplayEnd;\n\t\t\t\t\n\t\t\t\tif ( oSettings.oFeatures.bServerSide )\n\t\t\t\t{\n\t\t\t\t\tiStart = 0;\n\t\t\t\t\tiEnd = oSettings.aoData.length;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t\t{\n\t\t\t\t\tvar aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];\n\t\t\t\t\tvar nRow = aoData.nTr;\n\t\t\t\t\t\n\t\t\t\t\t/* Remove the old stripping classes and then add the new one */\n\t\t\t\t\tif ( iStrips !== 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar sStrip = oSettings.asStripClasses[ iRowCount % iStrips ];\n\t\t\t\t\t\tif ( aoData._sRowStripe != sStrip )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStrip );\n\t\t\t\t\t\t\taoData._sRowStripe = sStrip;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t/* Custom row callback function - might want to manipule the row */\n\t\t\t\t\tif ( typeof oSettings.fnRowCallback == \"function\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnRow = oSettings.fnRowCallback.call( oSettings.oInstance, nRow, \n\t\t\t\t\t\t\toSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j );\n\t\t\t\t\t\tif ( !nRow && !bRowError )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnLog( oSettings, 0, \"A node was not returned by fnRowCallback\" );\n\t\t\t\t\t\t\tbRowError = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tanRows.push( nRow );\n\t\t\t\t\tiRowCount++;\n\t\t\t\t\t\n\t\t\t\t\t/* If there is an open row - and it is attached to this parent - attach it on redraw */\n\t\t\t\t\tif ( iOpenRows !== 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( var k=0 ; k<iOpenRows ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( nRow == oSettings.aoOpenRows[k].nParent )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tanRows.push( oSettings.aoOpenRows[k].nTr );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\t\tanRows[ 0 ] = document.createElement( 'tr' );\n\t\t\t\t\n\t\t\t\tif ( typeof oSettings.asStripClasses[0] != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\tanRows[ 0 ].className = oSettings.asStripClasses[0];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar nTd = document.createElement( 'td' );\n\t\t\t\tnTd.setAttribute( 'valign', \"top\" );\n\t\t\t\tnTd.colSpan = _fnVisbleColumns( oSettings );\n\t\t\t\tnTd.className = oSettings.oClasses.sRowEmpty;\n\t\t\t\tif ( typeof oSettings.oLanguage.sEmptyTable != 'undefined' &&\n\t\t\t\t     oSettings.fnRecordsTotal() === 0 )\n\t\t\t\t{\n\t\t\t\t\tnTd.innerHTML = oSettings.oLanguage.sEmptyTable;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnTd.innerHTML = oSettings.oLanguage.sZeroRecords.replace(\n\t\t\t\t\t\t'_MAX_', oSettings.fnFormatNumber(oSettings.fnRecordsTotal()) );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tanRows[ iRowCount ].appendChild( nTd );\n\t\t\t}\n\t\t\t\n\t\t\t/* Callback the header and footer custom funcation if there is one */\n\t\t\tif ( typeof oSettings.fnHeaderCallback == 'function' )\n\t\t\t{\n\t\t\t\toSettings.fnHeaderCallback.call( oSettings.oInstance, $('>tr', oSettings.nTHead)[0], \n\t\t\t\t\t_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),\n\t\t\t\t\toSettings.aiDisplay );\n\t\t\t}\n\t\t\t\n\t\t\tif ( typeof oSettings.fnFooterCallback == 'function' )\n\t\t\t{\n\t\t\t\toSettings.fnFooterCallback.call( oSettings.oInstance, $('>tr', oSettings.nTFoot)[0], \n\t\t\t\t\t_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),\n\t\t\t\t\toSettings.aiDisplay );\n\t\t\t}\n\t\t\t\n\t\t\t/* \n\t\t\t * Need to remove any old row from the display - note we can't just empty the tbody using\n\t\t\t * $().html('') since this will unbind the jQuery event handlers (even although the node \n\t\t\t * still exists!) - equally we can't use innerHTML, since IE throws an exception.\n\t\t\t */\n\t\t\tvar\n\t\t\t\tnAddFrag = document.createDocumentFragment(),\n\t\t\t\tnRemoveFrag = document.createDocumentFragment(),\n\t\t\t\tnBodyPar, nTrs;\n\t\t\t\n\t\t\tif ( oSettings.nTBody )\n\t\t\t{\n\t\t\t\tnBodyPar = oSettings.nTBody.parentNode;\n\t\t\t\tnRemoveFrag.appendChild( oSettings.nTBody );\n\t\t\t\t\n\t\t\t\t/* When doing infinite scrolling, only remove child rows when sorting, filtering or start\n\t\t\t\t * up. When not infinite scroll, always do it.\n\t\t\t\t */\n\t\t\t\tif ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||\n\t\t\t\t \toSettings.bSorted || oSettings.bFiltered )\n\t\t\t\t{\n\t\t\t\t\tnTrs = oSettings.nTBody.childNodes;\n\t\t\t\t\tfor ( i=nTrs.length-1 ; i>=0 ; i-- )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTrs[i].parentNode.removeChild( nTrs[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Put the draw table into the dom */\n\t\t\t\tfor ( i=0, iLen=anRows.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tnAddFrag.appendChild( anRows[i] );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\toSettings.nTBody.appendChild( nAddFrag );\n\t\t\t\tif ( nBodyPar !== null )\n\t\t\t\t{\n\t\t\t\t\tnBodyPar.appendChild( oSettings.nTBody );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Call all required callback functions for the end of a draw */\n\t\t\tfor ( i=0, iLen=oSettings.aoDrawCallback.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toSettings.aoDrawCallback[i].fn.call( oSettings.oInstance, oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\t\toSettings.bSorted = false;\n\t\t\toSettings.bFiltered = false;\n\t\t\toSettings.bDrawing = false;\n\t\t\t\t\n\t\t\t/* On first draw, initilaisation is now complete */\n\t\t\tif ( typeof oSettings._bInitComplete == \"undefined\" )\n\t\t\t{\n\t\t\t\toSettings._bInitComplete = true;\n\t\t\t\t\n\t\t\t\tif ( typeof oSettings.fnInitComplete == 'function' &&\n\t\t\t\t\t   (oSettings.oFeatures.bServerSide || oSettings.sAjaxSource === null) )\n\t\t\t\t{\n\t\t\t\t\toSettings.fnInitComplete.call( oSettings.oInstance, oSettings );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnReDraw\n\t\t * Purpose:  Redraw the table - taking account of the various features which are enabled\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnReDraw( oSettings )\n\t\t{\n\t\t\tif ( oSettings.oFeatures.bSort )\n\t\t\t{\n\t\t\t\t/* Sorting will refilter and draw for us */\n\t\t\t\t_fnSort( oSettings, oSettings.oPreviousSearch );\n\t\t\t}\n\t\t\telse if ( oSettings.oFeatures.bFilter )\n\t\t\t{\n\t\t\t\t/* Filtering will redraw for us */\n\t\t\t\t_fnFilterComplete( oSettings, oSettings.oPreviousSearch );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t_fnDraw( oSettings );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnAjaxUpdate\n\t\t * Purpose:  Update the table using an Ajax call\n\t\t * Returns:  bool: block the table drawing or not\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnAjaxUpdate( oSettings )\n\t\t{\n\t\t\tif ( oSettings.bAjaxDataGet )\n\t\t\t{\n\t\t\t\t_fnProcessingDisplay( oSettings, true );\n\t\t\t\tvar iColumns = oSettings.aoColumns.length;\n\t\t\t\tvar aoData = [];\n\t\t\t\tvar i;\n\t\t\t\t\n\t\t\t\t/* Paging and general */\n\t\t\t\toSettings.iDraw++;\n\t\t\t\taoData.push( { \"name\": \"sEcho\",          \"value\": oSettings.iDraw } );\n\t\t\t\taoData.push( { \"name\": \"iColumns\",       \"value\": iColumns } );\n\t\t\t\taoData.push( { \"name\": \"sColumns\",       \"value\": _fnColumnOrdering(oSettings) } );\n\t\t\t\taoData.push( { \"name\": \"iDisplayStart\",  \"value\": oSettings._iDisplayStart } );\n\t\t\t\taoData.push( { \"name\": \"iDisplayLength\", \"value\": oSettings.oFeatures.bPaginate !== false ?\n\t\t\t\t\toSettings._iDisplayLength : -1 } );\n\t\t\t\t\n\t\t\t\t/* Column names */\n\t\t\t\tvar aNames = [];\n\t\t\t\tfor ( i=0 ; i<iColumns ; i++ )\n\t\t\t\t{\n\t\t\t\t\taNames.push( oSettings.aoColumns[i].sName );\n\t\t\t\t}\n\t\t\t\taoData.push( { \"name\": \"sNames\", \"value\": aNames.join(',') } );\n\t\t\t\t\n\t\t\t\t/* Filtering */\n\t\t\t\tif ( oSettings.oFeatures.bFilter !== false )\n\t\t\t\t{\n\t\t\t\t\taoData.push( { \"name\": \"sSearch\", \"value\": oSettings.oPreviousSearch.sSearch } );\n\t\t\t\t\taoData.push( { \"name\": \"bRegex\",  \"value\": oSettings.oPreviousSearch.bRegex } );\n\t\t\t\t\tfor ( i=0 ; i<iColumns ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\taoData.push( { \"name\": \"sSearch_\"+i,     \"value\": oSettings.aoPreSearchCols[i].sSearch } );\n\t\t\t\t\t\taoData.push( { \"name\": \"bRegex_\"+i,      \"value\": oSettings.aoPreSearchCols[i].bRegex } );\n\t\t\t\t\t\taoData.push( { \"name\": \"bSearchable_\"+i, \"value\": oSettings.aoColumns[i].bSearchable } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Sorting */\n\t\t\t\tif ( oSettings.oFeatures.bSort !== false )\n\t\t\t\t{\n\t\t\t\t\tvar iFixed = oSettings.aaSortingFixed !== null ? oSettings.aaSortingFixed.length : 0;\n\t\t\t\t\tvar iUser = oSettings.aaSorting.length;\n\t\t\t\t\taoData.push( { \"name\": \"iSortingCols\",   \"value\": iFixed+iUser } );\n\t\t\t\t\tfor ( i=0 ; i<iFixed ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\taoData.push( { \"name\": \"iSortCol_\"+i,  \"value\": oSettings.aaSortingFixed[i][0] } );\n\t\t\t\t\t\taoData.push( { \"name\": \"sSortDir_\"+i,  \"value\": oSettings.aaSortingFixed[i][1] } );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor ( i=0 ; i<iUser ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\taoData.push( { \"name\": \"iSortCol_\"+(i+iFixed),  \"value\": oSettings.aaSorting[i][0] } );\n\t\t\t\t\t\taoData.push( { \"name\": \"sSortDir_\"+(i+iFixed),  \"value\": oSettings.aaSorting[i][1] } );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor ( i=0 ; i<iColumns ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\taoData.push( { \"name\": \"bSortable_\"+i,  \"value\": oSettings.aoColumns[i].bSortable } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\toSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,\n\t\t\t\t\tfunction(json) {\n\t\t\t\t\t\t_fnAjaxUpdateDraw( oSettings, json );\n\t\t\t\t\t} );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnAjaxUpdateDraw\n\t\t * Purpose:  Data the data from the server (nuking the old) and redraw the table\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           object:json - json data return from the server.\n\t\t *             The following must be defined:\n\t\t *               iTotalRecords, iTotalDisplayRecords, aaData\n\t\t *             The following may be defined:\n\t\t *               sColumns\n\t\t */\n\t\tfunction _fnAjaxUpdateDraw ( oSettings, json )\n\t\t{\n\t\t\tif ( typeof json.sEcho != 'undefined' )\n\t\t\t{\n\t\t\t\t/* Protect against old returns over-writing a new one. Possible when you get\n\t\t\t\t * very fast interaction, and later queires are completed much faster\n\t\t\t\t */\n\t\t\t\tif ( json.sEcho*1 < oSettings.iDraw )\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\toSettings.iDraw = json.sEcho * 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif ( !oSettings.oScroll.bInfinite ||\n\t\t\t\t   (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )\n\t\t\t{\n\t\t\t\t_fnClearTable( oSettings );\n\t\t\t}\n\t\t\toSettings._iRecordsTotal = json.iTotalRecords;\n\t\t\toSettings._iRecordsDisplay = json.iTotalDisplayRecords;\n\t\t\t\n\t\t\t/* Determine if reordering is required */\n\t\t\tvar sOrdering = _fnColumnOrdering(oSettings);\n\t\t\tvar bReOrder = (typeof json.sColumns != 'undefined' && sOrdering !== \"\" && json.sColumns != sOrdering );\n\t\t\tif ( bReOrder )\n\t\t\t{\n\t\t\t\tvar aiIndex = _fnReOrderIndex( oSettings, json.sColumns );\n\t\t\t}\n\t\t\t\n\t\t\tfor ( var i=0, iLen=json.aaData.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tif ( bReOrder )\n\t\t\t\t{\n\t\t\t\t\t/* If we need to re-order, then create a new array with the correct order and add it */\n\t\t\t\t\tvar aData = [];\n\t\t\t\t\tfor ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )\n\t\t\t\t\t{\n\t\t\t\t\t\taData.push( json.aaData[i][ aiIndex[j] ] );\n\t\t\t\t\t}\n\t\t\t\t\t_fnAddData( oSettings, aData );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t/* No re-order required, sever got it \"right\" - just straight add */\n\t\t\t\t\t_fnAddData( oSettings, json.aaData[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\toSettings.bAjaxDataGet = false;\n\t\t\t_fnDraw( oSettings );\n\t\t\toSettings.bAjaxDataGet = true;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Options (features) HTML\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnAddOptionsHtml\n\t\t * Purpose:  Add the options to the page HTML for the table\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnAddOptionsHtml ( oSettings )\n\t\t{\n\t\t\t/*\n\t\t\t * Create a temporary, empty, div which we can later on replace with what we have generated\n\t\t\t * we do it this way to rendering the 'options' html offline - speed :-)\n\t\t\t */\n\t\t\tvar nHolding = document.createElement( 'div' );\n\t\t\toSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );\n\t\t\t\n\t\t\t/* \n\t\t\t * All DataTables are wrapped in a div - this is not currently optional - backwards \n\t\t\t * compatability. It can be removed if you don't want it.\n\t\t\t */\n\t\t\toSettings.nTableWrapper = document.createElement( 'div' );\n\t\t\toSettings.nTableWrapper.className = oSettings.oClasses.sWrapper;\n\t\t\tif ( oSettings.sTableId !== '' )\n\t\t\t{\n\t\t\t\toSettings.nTableWrapper.setAttribute( 'id', oSettings.sTableId+'_wrapper' );\n\t\t\t}\n\t\t\t\n\t\t\t/* Track where we want to insert the option */\n\t\t\tvar nInsertNode = oSettings.nTableWrapper;\n\t\t\t\n\t\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\t\tvar aDom = oSettings.sDom.split('');\n\t\t\tvar nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;\n\t\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t\t{\n\t\t\t\tiPushFeature = 0;\n\t\t\t\tcOption = aDom[i];\n\t\t\t\t\n\t\t\t\tif ( cOption == '<' )\n\t\t\t\t{\n\t\t\t\t\t/* New container div */\n\t\t\t\t\tnNewNode = document.createElement( 'div' );\n\t\t\t\t\t\n\t\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\t\tcNext = aDom[i+1];\n\t\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\t\tj = 2;\n\t\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* Replace jQuery UI constants */\n\t\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsAttr = \"fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsAttr = \"fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t\t */\n\t\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\t\tnNewNode.setAttribute('id', aSplit[0].substr(1, aSplit[0].length-1) );\n\t\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnNewNode.setAttribute('id', sAttr.substr(1, sAttr.length-1) );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tnInsertNode.appendChild( nNewNode );\n\t\t\t\t\tnInsertNode = nNewNode;\n\t\t\t\t}\n\t\t\t\telse if ( cOption == '>' )\n\t\t\t\t{\n\t\t\t\t\t/* End container div */\n\t\t\t\t\tnInsertNode = nInsertNode.parentNode;\n\t\t\t\t}\n\t\t\t\telse if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )\n\t\t\t\t{\n\t\t\t\t\t/* Length */\n\t\t\t\t\tnTmp = _fnFeatureHtmlLength( oSettings );\n\t\t\t\t\tiPushFeature = 1;\n\t\t\t\t}\n\t\t\t\telse if ( cOption == 'f' && oSettings.oFeatures.bFilter )\n\t\t\t\t{\n\t\t\t\t\t/* Filter */\n\t\t\t\t\tnTmp = _fnFeatureHtmlFilter( oSettings );\n\t\t\t\t\tiPushFeature = 1;\n\t\t\t\t}\n\t\t\t\telse if ( cOption == 'r' && oSettings.oFeatures.bProcessing )\n\t\t\t\t{\n\t\t\t\t\t/* pRocessing */\n\t\t\t\t\tnTmp = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t\t\tiPushFeature = 1;\n\t\t\t\t}\n\t\t\t\telse if ( cOption == 't' )\n\t\t\t\t{\n\t\t\t\t\t/* Table */\n\t\t\t\t\tnTmp = _fnFeatureHtmlTable( oSettings );\n\t\t\t\t\tiPushFeature = 1;\n\t\t\t\t}\n\t\t\t\telse if ( cOption ==  'i' && oSettings.oFeatures.bInfo )\n\t\t\t\t{\n\t\t\t\t\t/* Info */\n\t\t\t\t\tnTmp = _fnFeatureHtmlInfo( oSettings );\n\t\t\t\t\tiPushFeature = 1;\n\t\t\t\t}\n\t\t\t\telse if ( cOption == 'p' && oSettings.oFeatures.bPaginate )\n\t\t\t\t{\n\t\t\t\t\t/* Pagination */\n\t\t\t\t\tnTmp = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t\t\tiPushFeature = 1;\n\t\t\t\t}\n\t\t\t\telse if ( _oExt.aoFeatures.length !== 0 )\n\t\t\t\t{\n\t\t\t\t\t/* Plug-in features */\n\t\t\t\t\tvar aoFeatures = _oExt.aoFeatures;\n\t\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnTmp = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\t\tif ( nTmp )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tiPushFeature = 1;\n\t\t\t\t\t\t\t}\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\t\n\t\t\t\t/* Add to the 2D features array */\n\t\t\t\tif ( iPushFeature == 1 && nTmp !== null )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof oSettings.aanFeatures[cOption] != 'object' )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aanFeatures[cOption] = [];\n\t\t\t\t\t}\n\t\t\t\t\toSettings.aanFeatures[cOption].push( nTmp );\n\t\t\t\t\tnInsertNode.appendChild( nTmp );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\t\tnHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );\n\t\t}\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Feature: Filtering\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnFeatureHtmlTable\n\t\t * Purpose:  Add any control elements for the table - specifically scrolling\n\t\t * Returns:  node: - Node to add to the DOM\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnFeatureHtmlTable ( oSettings )\n\t\t{\n\t\t\t/* Chack if scrolling is enabled or not - if not then leave the DOM unaltered */\n\t\t\tif ( oSettings.oScroll.sX === \"\" && oSettings.oScroll.sY === \"\" )\n\t\t\t{\n\t\t\t\treturn oSettings.nTable;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * The HTML structure that we want to generate in this function is:\n\t\t\t *  div - nScroller\n\t\t\t *    div - nScrollHead\n\t\t\t *      div - nScrollHeadInner\n\t\t\t *        table - nScrollHeadTable\n\t\t\t *          thead - nThead\n\t\t\t *    div - nScrollBody\n\t\t\t *      table - oSettings.nTable\n\t\t\t *        thead - nTheadSize\n\t\t\t *        tbody - nTbody\n\t\t\t *    div - nScrollFoot\n\t\t\t *      div - nScrollFootInner\n\t\t\t *        table - nScrollFootTable\n\t\t\t *          tfoot - nTfoot\n\t\t\t */\n\t\t\tvar\n\t\t\t \tnScroller = document.createElement('div'),\n\t\t\t \tnScrollHead = document.createElement('div'),\n\t\t\t \tnScrollHeadInner = document.createElement('div'),\n\t\t\t \tnScrollBody = document.createElement('div'),\n\t\t\t \tnScrollFoot = document.createElement('div'),\n\t\t\t \tnScrollFootInner = document.createElement('div'),\n\t\t\t \tnScrollHeadTable = oSettings.nTable.cloneNode(false),\n\t\t\t \tnScrollFootTable = oSettings.nTable.cloneNode(false),\n\t\t\t\tnThead = oSettings.nTable.getElementsByTagName('thead')[0],\n\t\t\t \tnTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null : \n\t\t\t\t\toSettings.nTable.getElementsByTagName('tfoot')[0],\n\t\t\t\toClasses = (typeof oInit.bJQueryUI != 'undefined' && oInit.bJQueryUI) ?\n\t\t\t \t\t_oExt.oJUIClasses : _oExt.oStdClasses;\n\t\t\t\n\t\t\tnScrollHead.appendChild( nScrollHeadInner );\n\t\t\tnScrollFoot.appendChild( nScrollFootInner );\n\t\t\tnScrollBody.appendChild( oSettings.nTable );\n\t\t\tnScroller.appendChild( nScrollHead );\n\t\t\tnScroller.appendChild( nScrollBody );\n\t\t\tnScrollHeadInner.appendChild( nScrollHeadTable );\n\t\t\tnScrollHeadTable.appendChild( nThead );\n\t\t\tif ( nTfoot !== null )\n\t\t\t{\n\t\t\t\tnScroller.appendChild( nScrollFoot );\n\t\t\t\tnScrollFootInner.appendChild( nScrollFootTable );\n\t\t\t\tnScrollFootTable.appendChild( nTfoot );\n\t\t\t}\n\t\t\t\n\t\t\tnScroller.className = oClasses.sScrollWrapper;\n\t\t\tnScrollHead.className = oClasses.sScrollHead;\n\t\t\tnScrollHeadInner.className = oClasses.sScrollHeadInner;\n\t\t\tnScrollBody.className = oClasses.sScrollBody;\n\t\t\tnScrollFoot.className = oClasses.sScrollFoot;\n\t\t\tnScrollFootInner.className = oClasses.sScrollFootInner;\n\t\t\t\n\t\t\tnScrollHead.style.overflow = \"hidden\";\n\t\t\tnScrollHead.style.position = \"relative\";\n\t\t\tnScrollFoot.style.overflow = \"hidden\";\n\t\t\tnScrollBody.style.overflow = \"auto\";\n\t\t\tnScrollHead.style.border = \"0\";\n\t\t\tnScrollFoot.style.border = \"0\";\n\t\t\tnScrollHeadInner.style.width = \"150%\"; /* will be overwritten */\n\t\t\t\n\t\t\t/* Modify attributes to respect the clones */\n\t\t\tnScrollHeadTable.removeAttribute('id');\n\t\t\tnScrollHeadTable.style.marginLeft = \"0\";\n\t\t\toSettings.nTable.style.marginLeft = \"0\";\n\t\t\tif ( nTfoot !== null )\n\t\t\t{\n\t\t\t\tnScrollFootTable.removeAttribute('id');\n\t\t\t\tnScrollFootTable.style.marginLeft = \"0\";\n\t\t\t}\n\t\t\t\n\t\t\t/* Move any caption elements from the body to the header */\n\t\t\tvar nCaptions = $('>caption', oSettings.nTable);\n\t\t\tfor ( var i=0, iLen=nCaptions.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tnScrollHeadTable.appendChild( nCaptions[i] );\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Sizing\n\t\t\t */\n\t\t\t/* When xscrolling add the width and a scroller to move the header with the body */\n\t\t\tif ( oSettings.oScroll.sX !== \"\" )\n\t\t\t{\n\t\t\t\tnScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );\n\t\t\t\tnScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );\n\t\t\t\t\n\t\t\t\tif ( nTfoot !== null )\n\t\t\t\t{\n\t\t\t\t\tnScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* When the body is scrolled, then we also want to scroll the headers */\n\t\t\t\t$(nScrollBody).scroll( function (e) {\n\t\t\t\t\tnScrollHead.scrollLeft = this.scrollLeft;\n\t\t\t\t\t\n\t\t\t\t\tif ( nTfoot !== null )\n\t\t\t\t\t{\n\t\t\t\t\t\tnScrollFoot.scrollLeft = this.scrollLeft;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\t/* When yscrolling, add the height */\n\t\t\tif ( oSettings.oScroll.sY !== \"\" )\n\t\t\t{\n\t\t\t\tnScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );\n\t\t\t}\n\t\t\t\n\t\t\t/* Redraw - align columns across the tables */\n\t\t\toSettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\t\"sName\": \"scrolling\"\n\t\t\t} );\n\t\t\t\n\t\t\t/* Infinite scrolling event handlers */\n\t\t\tif ( oSettings.oScroll.bInfinite )\n\t\t\t{\n\t\t\t\t$(nScrollBody).scroll( function() {\n\t\t\t\t\t/* Use a blocker to stop scrolling from loading more data while other data is still loading */\n\t\t\t\t\tif ( !oSettings.bDrawing )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Check if we should load the next data set */\n\t\t\t\t\t\tif ( $(this).scrollTop() + $(this).height() > \n\t\t\t\t\t\t\t$(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t/* Only do the redraw if we have to - we might be at the end of the data */\n\t\t\t\t\t\t\tif ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t_fnPageChange( oSettings, 'next' );\n\t\t\t\t\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t\t\t\t\t_fnDraw( oSettings );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\toSettings.nScrollHead = nScrollHead;\n\t\t\toSettings.nScrollFoot = nScrollFoot;\n\t\t\t\n\t\t\treturn nScroller;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnScrollDraw\n\t\t * Purpose:  Update the various tables for resizing\n\t\t * Returns:  node: - Node to add to the DOM\n\t\t * Inputs:   object:o - dataTables settings object\n\t\t * Notes:    It's a bit of a pig this function, but basically the idea to:\n\t\t *   1. Re-create the table inside the scrolling div\n\t\t *   2. Take live measurements from the DOM\n\t\t *   3. Apply the measurements\n\t\t *   4. Clean up\n\t\t */\n\t\tfunction _fnScrollDraw ( o )\n\t\t{\n\t\t\tvar\n\t\t\t\tnScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],\n\t\t\t\tnScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],\n\t\t\t\tnScrollBody = o.nTable.parentNode,\n\t\t\t\ti, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,\n\t\t\t\tiWidth, aApplied=[], iSanityWidth;\n\t\t\t\n\t\t\t/*\n\t\t\t * 1. Re-create the table inside the scrolling div\n\t\t\t */\n\t\t\t\n\t\t\t/* Remove the old minimised thead and tfoot elements in the inner table */\n\t\t\tvar nTheadSize = o.nTable.getElementsByTagName('thead');\n\t\t\tif ( nTheadSize.length > 0 )\n\t\t\t{\n\t\t\t\to.nTable.removeChild( nTheadSize[0] );\n\t\t\t}\n\t\t\t\n\t\t\tif ( o.nTFoot !== null )\n\t\t\t{\n\t\t\t\t/* Remove the old minimised footer element in the cloned header */\n\t\t\t\tvar nTfootSize = o.nTable.getElementsByTagName('tfoot');\n\t\t\t\tif ( nTfootSize.length > 0 )\n\t\t\t\t{\n\t\t\t\t\to.nTable.removeChild( nTfootSize[0] );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Clone the current header and footer elements and then place it into the inner table */\n\t\t\tnTheadSize = o.nTHead.cloneNode(true);\n\t\t\to.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );\n\t\t\t\n\t\t\tif ( o.nTFoot !== null )\n\t\t\t{\n\t\t\t\tnTfootSize = o.nTFoot.cloneNode(true);\n\t\t\t\to.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t\t */\n\t\t\t\n\t\t\t/* Remove old sizing and apply the calculated column widths\n\t\t\t * Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t\t * calclated sizes to this header\n\t\t\t */\n\t\t\tvar nThs = _fnGetUniqueThs( nTheadSize );\n\t\t\tfor ( i=0, iLen=nThs.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tiVis = _fnVisibleToColumnIndex( o, i );\n\t\t\t\tnThs[i].style.width = o.aoColumns[iVis].sWidth;\n\t\t\t}\n\t\t\t\n\t\t\tif ( o.nTFoot !== null )\n\t\t\t{\n\t\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\t\tn.style.width = \"\";\n\t\t\t\t}, nTfootSize.getElementsByTagName('tr') );\n\t\t\t}\n\t\t\t\n\t\t\t/* Size the table as a whole */\n\t\t\tiSanityWidth = $(o.nTable).outerWidth();\n\t\t\tif ( o.oScroll.sX === \"\" )\n\t\t\t{\n\t\t\t\t/* No x scrolling */\n\t\t\t\to.nTable.style.width = \"100%\";\n\t\t\t\t\n\t\t\t\t/* I know this is rubbish - but IE7 will make the width of the table when 100% include\n\t\t\t\t * the scrollbar - which is shouldn't. This needs feature detection in future - to do\n\t\t\t\t */\n\t\t\t\tif ( $.browser.msie && $.browser.version <= 7 )\n\t\t\t\t{\n\t\t\t\t\to.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth()-o.oScroll.iBarWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ( o.oScroll.sXInner !== \"\" )\n\t\t\t\t{\n\t\t\t\t\t/* x scroll inner has been given - use it */\n\t\t\t\t\to.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);\n\t\t\t\t}\n\t\t\t\telse if ( iSanityWidth == $(nScrollBody).width() &&\n\t\t\t\t   $(nScrollBody).height() < $(o.nTable).height() )\n\t\t\t\t{\n\t\t\t\t\t/* There is y-scrolling - try to take account of the y scroll bar */\n\t\t\t\t\to.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );\n\t\t\t\t\tif ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Not possible to take account of it */\n\t\t\t\t\t\to.nTable.style.width = _fnStringToCss( iSanityWidth );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t/* All else fails */\n\t\t\t\t\to.nTable.style.width = _fnStringToCss( iSanityWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Recalculate the sanity width - now that we've applied the required width, before it was\n\t\t\t * a temporary variable. This is required because the column width calculation is done\n\t\t\t * before this table DOM is created.\n\t\t\t */\n\t\t\tiSanityWidth = $(o.nTable).outerWidth();\n\t\t\t\n\t\t\t/* We want the hidden header to have zero height, so remove padding and borders. Then\n\t\t\t * set the width based on the real headers\n\t\t\t */\n\t\t\tanHeadToSize = o.nTHead.getElementsByTagName('tr');\n\t\t\tanHeadSizers = nTheadSize.getElementsByTagName('tr');\n\t\t\t\n\t\t\t_fnApplyToChildren( function(nSizer, nToSize) {\n\t\t\t\toStyle = nSizer.style;\n\t\t\t\toStyle.paddingTop = \"0\";\n\t\t\t\toStyle.paddingBottom = \"0\";\n\t\t\t\toStyle.borderTopWidth = \"0\";\n\t\t\t\toStyle.borderBottomWidth = \"0\";\n\t\t\t\toStyle.height = 0;\n\t\t\t\t\n\t\t\t\tiWidth = $(nSizer).width();\n\t\t\t\tnToSize.style.width = _fnStringToCss( iWidth );\n\t\t\t\taApplied.push( iWidth );\n\t\t\t}, anHeadSizers, anHeadToSize );\n\t\t\t$(anHeadSizers).height(0);\n\t\t\t\n\t\t\tif ( o.nTFoot !== null )\n\t\t\t{\n\t\t\t\t/* Clone the current footer and then place it into the body table as a \"hidden header\" */\n\t\t\t\tanFootSizers = nTfootSize.getElementsByTagName('tr');\n\t\t\t\tanFootToSize = o.nTFoot.getElementsByTagName('tr');\n\t\t\t\t\n\t\t\t\t_fnApplyToChildren( function(nSizer, nToSize) {\n\t\t\t\t\toStyle = nSizer.style;\n\t\t\t\t\toStyle.paddingTop = \"0\";\n\t\t\t\t\toStyle.paddingBottom = \"0\";\n\t\t\t\t\toStyle.borderTopWidth = \"0\";\n\t\t\t\t\toStyle.borderBottomWidth = \"0\";\n\t\t\t\t\t\n\t\t\t\t\tiWidth = $(nSizer).width();\n\t\t\t\t\tnToSize.style.width = _fnStringToCss( iWidth );\n\t\t\t\t\taApplied.push( iWidth );\n\t\t\t\t}, anFootSizers, anFootToSize );\n\t\t\t\t$(anFootSizers).height(0);\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * 3. Apply the measurements\n\t\t\t */\n\t\t\t\n\t\t\t/* \"Hide\" the header and footer that we used for the sizing. We want to also fix their width\n\t\t\t * to what they currently are\n\t\t\t */\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tnSizer.innerHTML = \"\";\n\t\t\t\tnSizer.style.width = _fnStringToCss( aApplied.shift() );\n\t\t\t}, anHeadSizers );\n\t\t\t\n\t\t\tif ( o.nTFoot !== null )\n\t\t\t{\n\t\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\t\tnSizer.innerHTML = \"\";\n\t\t\t\t\tnSizer.style.width = _fnStringToCss( aApplied.shift() );\n\t\t\t\t}, anFootSizers );\n\t\t\t}\n\t\t\t\n\t\t\t/* Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t\t * misalignment\n\t\t\t */\n\t\t\tif ( $(o.nTable).outerWidth() < iSanityWidth )\n\t\t\t{\n\t\t\t\tif ( o.oScroll.sX === \"\" )\n\t\t\t\t{\n\t\t\t\t\t_fnLog( o, 1, \"The table cannot fit into the current element which will cause column\"+\n\t\t\t\t\t\t\" misalignment. It is suggested that you enable x-scrolling or increase the width\"+\n\t\t\t\t\t\t\" the table has in which to be drawn\" );\n\t\t\t\t}\n\t\t\t\telse if ( o.oScroll.sXInner !== \"\" )\n\t\t\t\t{\n\t\t\t\t\t_fnLog( o, 1, \"The table cannot fit into the current element which will cause column\"+\n\t\t\t\t\t\t\" misalignment. It is suggested that you increase the sScrollXInner property to\"+\n\t\t\t\t\t\t\" allow it to draw in a larger area, or simply remove that parameter to allow\"+\n\t\t\t\t\t\t\" automatic calculation\" );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t/*\n\t\t\t * 4. Clean up\n\t\t\t */\n\t\t\t\n\t\t\tif ( o.oScroll.sY === \"\" )\n\t\t\t{\n\t\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t\t */\n\t\t\t\tif ( $.browser.msie && $.browser.version <= 7 )\n\t\t\t\t{\n\t\t\t\t\tnScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif ( o.oScroll.sY !== \"\" && o.oScroll.bCollapse )\n\t\t\t{\n\t\t\t\tnScrollBody.style.height = _fnStringToCss( o.oScroll.sY );\n\t\t\t\t\n\t\t\t\tvar iExtra = (o.oScroll.sX !== \"\" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?\n\t\t\t\t \to.oScroll.iBarWidth : 0;\n\t\t\t\tif ( o.nTable.offsetHeight < nScrollBody.offsetHeight )\n\t\t\t\t{\n\t\t\t\t\tnScrollBody.style.height = _fnStringToCss( $(o.nTable).height()+iExtra );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Finally set the width's of the header and footer tables */\n\t\t\tvar iOuterWidth = $(o.nTable).outerWidth();\n\t\t\tnScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );\n\t\t\tnScrollHeadInner.style.width = _fnStringToCss( iOuterWidth+o.oScroll.iBarWidth );\n\t\t\tnScrollHeadInner.parentNode.style.width = _fnStringToCss( $(nScrollBody).width() );\n\t\t\t\n\t\t\tif ( o.nTFoot !== null )\n\t\t\t{\n\t\t\t\tvar\n\t\t\t\t\tnScrollFootInner = o.nScrollFoot.getElementsByTagName('div')[0],\n\t\t\t\t\tnScrollFootTable = nScrollFootInner.getElementsByTagName('table')[0];\n\t\t\t\t\n\t\t\t\tnScrollFootInner.style.width = _fnStringToCss( o.nTable.offsetWidth+o.oScroll.iBarWidth );\n\t\t\t\tnScrollFootTable.style.width = _fnStringToCss( o.nTable.offsetWidth );\n\t\t\t}\n\t\t\t\n\t\t\t/* If sorting or filtering has occured, jump the scrolling back to the top */\n\t\t\tif ( o.bSorted || o.bFiltered )\n\t\t\t{\n\t\t\t\tnScrollBody.scrollTop = 0;\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnAjustColumnSizing\n\t\t * Purpose:  Ajust the table column widths for new data\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t * Notes:    You would probably want to do a redraw after calling this function!\n\t\t */\n\t\tfunction _fnAjustColumnSizing ( oSettings )\n\t\t{\n\t\t\t/* Not interested in doing column width calculation if autowidth is disabled */\n\t\t\tif ( oSettings.oFeatures.bAutoWidth === false )\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\t\t\t_fnCalculateColumnWidths( oSettings );\n\t\t\tfor ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Feature: Filtering\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnFeatureHtmlFilter\n\t\t * Purpose:  Generate the node required for filtering text\n\t\t * Returns:  node\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnFeatureHtmlFilter ( oSettings )\n\t\t{\n\t\t\tvar nFilter = document.createElement( 'div' );\n\t\t\tif ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.f == \"undefined\" )\n\t\t\t{\n\t\t\t\tnFilter.setAttribute( 'id', oSettings.sTableId+'_filter' );\n\t\t\t}\n\t\t\tnFilter.className = oSettings.oClasses.sFilter;\n\t\t\tvar sSpace = oSettings.oLanguage.sSearch===\"\" ? \"\" : \" \";\n\t\t\tnFilter.innerHTML = oSettings.oLanguage.sSearch+sSpace+'<input type=\"text\" />';\n\t\t\t\n\t\t\tvar jqFilter = $(\"input\", nFilter);\n\t\t\tjqFilter.val( oSettings.oPreviousSearch.sSearch.replace('\"','&quot;') );\n\t\t\tjqFilter.keyup( function(e) {\n\t\t\t\t/* Update all other filter input elements for the new display */\n\t\t\t\tvar n = oSettings.aanFeatures.f;\n\t\t\t\tfor ( var i=0, iLen=n.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( n[i] != this.parentNode )\n\t\t\t\t\t{\n\t\t\t\t\t\t$('input', n[i]).val( this.value );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Now do the filter */\n\t\t\t\tif ( this.value != oSettings.oPreviousSearch.sSearch )\n\t\t\t\t{\n\t\t\t\t\t_fnFilterComplete( oSettings, { \n\t\t\t\t\t\t\"sSearch\": this.value, \n\t\t\t\t\t\t\"bRegex\":  oSettings.oPreviousSearch.bRegex,\n\t\t\t\t\t\t\"bSmart\":  oSettings.oPreviousSearch.bSmart \n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t\t\n\t\t\tjqFilter.keypress( function(e) {\n\t\t\t\t/* Prevent default */\n\t\t\t\tif ( e.keyCode == 13 )\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} );\n\t\t\t\n\t\t\treturn nFilter;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnFilterComplete\n\t\t * Purpose:  Filter the table using both the global filter and column based filtering\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           object:oSearch: search information\n\t\t *           int:iForce - optional - force a research of the master array (1) or not (undefined or 0)\n\t\t */\n\t\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t\t{\n\t\t\t/* Filter on everything */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart );\n\t\t\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, oSettings.aoPreSearchCols[i].sSearch, i, \n\t\t\t\t\toSettings.aoPreSearchCols[i].bRegex, oSettings.aoPreSearchCols[i].bSmart );\n\t\t\t}\n\t\t\t\n\t\t\t/* Custom filtering */\n\t\t\tif ( _oExt.afnFiltering.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnFilterCustom( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* Tell the draw function we have been filtering */\n\t\t\toSettings.bFiltered = true;\n\t\t\t\n\t\t\t/* Redraw the table */\n\t\t\toSettings._iDisplayStart = 0;\n\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t_fnDraw( oSettings );\n\t\t\t\n\t\t\t/* Rebuild search array 'offline' */\n\t\t\t_fnBuildSearchArray( oSettings, 0 );\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnFilterCustom\n\t\t * Purpose:  Apply custom filtering functions\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnFilterCustom( oSettings )\n\t\t{\n\t\t\tvar afnFilters = _oExt.afnFiltering;\n\t\t\tfor ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar iCorrector = 0;\n\t\t\t\tfor ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tvar iDisIndex = oSettings.aiDisplay[j-iCorrector];\n\t\t\t\t\t\n\t\t\t\t\t/* Check if we should use this row based on the filtering function */\n\t\t\t\t\tif ( !afnFilters[i]( oSettings, oSettings.aoData[iDisIndex]._aData, iDisIndex ) )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aiDisplay.splice( j-iCorrector, 1 );\n\t\t\t\t\t\tiCorrector++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnFilterColumn\n\t\t * Purpose:  Filter the table on a per-column basis\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           string:sInput - string to filter on\n\t\t *           int:iColumn - column to filter\n\t\t *           bool:bRegex - treat search string as a regular expression or not\n\t\t *           bool:bSmart - use smart filtering or not\n\t\t */\n\t\tfunction _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart )\n\t\t{\n\t\t\tif ( sInput === \"\" )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar iIndexCorrector = 0;\n\t\t\tvar rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart );\n\t\t\t\n\t\t\tfor ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tvar sData = _fnDataToSearch( oSettings.aoData[ oSettings.aiDisplay[i] ]._aData[iColumn],\n\t\t\t\t\toSettings.aoColumns[iColumn].sType );\n\t\t\t\tif ( ! rpSearch.test( sData ) )\n\t\t\t\t{\n\t\t\t\t\toSettings.aiDisplay.splice( i, 1 );\n\t\t\t\t\tiIndexCorrector++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnFilter\n\t\t * Purpose:  Filter the data table based on user input and draw the table\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           string:sInput - string to filter on\n\t\t *           int:iForce - optional - force a research of the master array (1) or not (undefined or 0)\n\t\t *           bool:bRegex - treat as a regular expression or not\n\t\t *           bool:bSmart - perform smart filtering or not\n\t\t */\n\t\tfunction _fnFilter( oSettings, sInput, iForce, bRegex, bSmart )\n\t\t{\n\t\t\tvar i;\n\t\t\tvar rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart );\n\t\t\t\n\t\t\t/* Check if we are forcing or not - optional parameter */\n\t\t\tif ( typeof iForce == 'undefined' || iForce === null )\n\t\t\t{\n\t\t\t\tiForce = 0;\n\t\t\t}\n\t\t\t\n\t\t\t/* Need to take account of custom filtering functions - always filter */\n\t\t\tif ( _oExt.afnFiltering.length !== 0 )\n\t\t\t{\n\t\t\t\tiForce = 1;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * If the input is blank - we want the full data set\n\t\t\t */\n\t\t\tif ( sInput.length <= 0 )\n\t\t\t{\n\t\t\t\toSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/*\n\t\t\t\t * We are starting a new search or the new search string is smaller \n\t\t\t\t * then the old one (i.e. delete). Search from the master array\n\t\t\t \t */\n\t\t\t\tif ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||\n\t\t\t\t\t   oSettings.oPreviousSearch.sSearch.length > sInput.length || iForce == 1 ||\n\t\t\t\t\t   sInput.indexOf(oSettings.oPreviousSearch.sSearch) !== 0 )\n\t\t\t\t{\n\t\t\t\t\t/* Nuke the old display array - we are going to rebuild it */\n\t\t\t\t\toSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);\n\t\t\t\t\t\n\t\t\t\t\t/* Force a rebuild of the search array */\n\t\t\t\t\t_fnBuildSearchArray( oSettings, 1 );\n\t\t\t\t\t\n\t\t\t\t\t/* Search through all records to populate the search array\n\t\t\t\t\t * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 \n\t\t\t\t\t * mapping\n\t\t\t\t\t */\n\t\t\t\t\tfor ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( rpSearch.test(oSettings.asDataSearch[i]) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t  }\n\t\t\t  else\n\t\t\t\t{\n\t\t\t  \t/* Using old search array - refine it - do it this way for speed\n\t\t\t  \t * Don't have to search the whole master array again\n\t\t\t \t\t */\n\t\t\t  \tvar iIndexCorrector = 0;\n\t\t\t  \t\n\t\t\t  \t/* Search the current results */\n\t\t\t  \tfor ( i=0 ; i<oSettings.asDataSearch.length ; i++ )\n\t\t\t\t\t{\n\t\t\t  \t\tif ( ! rpSearch.test(oSettings.asDataSearch[i]) )\n\t\t\t\t\t\t{\n\t\t\t  \t\t\toSettings.aiDisplay.splice( i-iIndexCorrector, 1 );\n\t\t\t  \t\t\tiIndexCorrector++;\n\t\t\t  \t\t}\n\t\t\t  \t}\n\t\t\t  }\n\t\t\t}\n\t\t\toSettings.oPreviousSearch.sSearch = sInput;\n\t\t\toSettings.oPreviousSearch.bRegex = bRegex;\n\t\t\toSettings.oPreviousSearch.bSmart = bSmart;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnBuildSearchArray\n\t\t * Purpose:  Create an array which can be quickly search through\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           int:iMaster - use the master data array - optional\n\t\t */\n\t\tfunction _fnBuildSearchArray ( oSettings, iMaster )\n\t\t{\n\t\t\t/* Clear out the old data */\n\t\t\toSettings.asDataSearch.splice( 0, oSettings.asDataSearch.length );\n\t\t\t\n\t\t\tvar aArray = (typeof iMaster != 'undefined' && iMaster == 1) ?\n\t\t\t \toSettings.aiDisplayMaster : oSettings.aiDisplay;\n\t\t\t\n\t\t\tfor ( var i=0, iLen=aArray.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toSettings.asDataSearch[i] = _fnBuildSearchRow( oSettings, \n\t\t\t\t\toSettings.aoData[ aArray[i] ]._aData );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnBuildSearchRow\n\t\t * Purpose:  Create a searchable string from a single data row\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           array:aData - aoData[]._aData array to use for the data to search\n\t\t */\n\t\tfunction _fnBuildSearchRow( oSettings, aData )\n\t\t{\n\t\t\tvar sSearch = '';\n\t\t\tvar nTmp = document.createElement('div');\n\t\t\t\n\t\t\tfor ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aoColumns[j].bSearchable )\n\t\t\t\t{\n\t\t\t\t\tvar sData = aData[j];\n\t\t\t\t\tsSearch += _fnDataToSearch( sData, oSettings.aoColumns[j].sType )+'  ';\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* If it looks like there is an HTML entity in the string, attempt to decode it */\n\t\t\tif ( sSearch.indexOf('&') !== -1 )\n\t\t\t{\n\t\t\t\tnTmp.innerHTML = sSearch;\n\t\t\t\tsSearch = nTmp.textContent ? nTmp.textContent : nTmp.innerText;\n\t\t\t\t\n\t\t\t\t/* IE and Opera appear to put an newline where there is a <br> tag - remove it */\n\t\t\t\tsSearch = sSearch.replace(/\\n/g,\" \").replace(/\\r/g,\"\");\n\t\t\t}\n\t\t\t\n\t\t\treturn sSearch;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnFilterCreateSearch\n\t\t * Purpose:  Build a regular expression object suitable for searching a table\n\t\t * Returns:  RegExp: - constructed object\n\t\t * Inputs:   string:sSearch - string to search for\n\t\t *           bool:bRegex - treat as a regular expression or not\n\t\t *           bool:bSmart - perform smart filtering or not\n\t\t */\n\t\tfunction _fnFilterCreateSearch( sSearch, bRegex, bSmart )\n\t\t{\n\t\t\tvar asSearch, sRegExpString;\n\t\t\t\n\t\t\tif ( bSmart )\n\t\t\t{\n\t\t\t\t/* Generate the regular expression to use. Something along the lines of:\n\t\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo\\b)(?=.*?\\bthree\\b).*$\n\t\t\t\t */\n\t\t\t\tasSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );\n\t\t\t\tsRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';\n\t\t\t\treturn new RegExp( sRegExpString, \"i\" );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );\n\t\t\t\treturn new RegExp( sSearch, \"i\" );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnDataToSearch\n\t\t * Purpose:  Convert raw data into something that the user can search on\n\t\t * Returns:  string: - search string\n\t\t * Inputs:   string:sData - data to be modified\n\t\t *           string:sType - data type\n\t\t */\n\t\tfunction _fnDataToSearch ( sData, sType )\n\t\t{\n\t\t\tif ( typeof _oExt.ofnSearch[sType] == \"function\" )\n\t\t\t{\n\t\t\t\treturn _oExt.ofnSearch[sType]( sData );\n\t\t\t}\n\t\t\telse if ( sType == \"html\" )\n\t\t\t{\n\t\t\t\treturn sData.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t}\n\t\t\telse if ( typeof sData == \"string\" )\n\t\t\t{\n\t\t\t\treturn sData.replace(/\\n/g,\" \");\n\t\t\t}\n\t\t\treturn sData;\n\t\t}\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Feature: Sorting\n\t\t */\n\t\t\n\t\t/*\n\t \t * Function: _fnSort\n\t\t * Purpose:  Change the order of the table\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           bool:bApplyClasses - optional - should we apply classes or not\n\t\t * Notes:    We always sort the master array and then apply a filter again\n\t\t *   if it is needed. This probably isn't optimal - but atm I can't think\n\t\t *   of any other way which is (each has disadvantages). we want to sort aiDisplayMaster - \n\t\t *   but according to aoData[]._aData\n\t\t */\n\t\tfunction _fnSort ( oSettings, bApplyClasses )\n\t\t{\n\t\t\tvar aaSort = [];\n\t\t\tvar oSort = _oExt.oSort;\n\t\t\tvar aoData = oSettings.aoData;\n\t\t\tvar iDataSort;\n\t\t\tvar iDataType;\n\t\t\tvar i, j, jLen;\n\t\t\t\n\t\t\t/* No sorting required if server-side or no sorting array */\n\t\t\tif ( !oSettings.oFeatures.bServerSide && \n\t\t\t\t(oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )\n\t\t\t{\n\t\t\t\tif ( oSettings.aaSortingFixed !== null )\n\t\t\t\t{\n\t\t\t\t\taaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\taaSort = oSettings.aaSorting.slice();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* If there is a sorting data type, and a fuction belonging to it, then we need to\n\t\t\t\t * get the data from the developer's function and apply it for this column\n\t\t\t\t */\n\t\t\t\tfor ( i=0 ; i<aaSort.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\tvar iColumn = aaSort[i][0];\n\t\t\t\t\tvar iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );\n\t\t\t\t\tvar sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;\n\t\t\t\t\tif ( typeof _oExt.afnSortData[sDataType] != 'undefined' )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aData = _oExt.afnSortData[sDataType]( oSettings, iColumn, iVisColumn );\n\t\t\t\t\t\tfor ( j=0, jLen=aoData.length ; j<jLen ; j++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taoData[j]._aData[iColumn] = aData[j];\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\t/* DataTables offers two different methods for doing the 2D array sorting over multiple\n\t\t\t\t * columns. The first is to construct a function dynamically, and then evaluate and run\n\t\t\t\t * the function, while the second has no need for evalulation, but is a little bit slower.\n\t\t\t\t * This is used for environments which do not allow eval() for code execuation such as AIR\n\t\t\t\t */\n\t\t\t\tif ( !window.runtime )\n\t\t\t\t{\n\t\t\t\t\t/* Dynamically created sorting function. Based on the information that we have, we can\n\t\t\t\t\t * create a sorting function as if it were specifically written for this sort. Here we\n\t\t\t\t\t * want to build a function something like (for two column sorting):\n\t\t\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t\t\t *  \tvar iTest;\n\t\t\t\t\t *  \tiTest = oSort['string-asc']('data11', 'data12');\n\t\t\t\t\t *  \tif (iTest === 0)\n\t\t\t\t\t *  \t\tiTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t\t\t *  \t\tif (iTest === 0)\n\t\t\t\t\t *  \t\t\treturn oSort['numeric-desc'](1,2);\n\t\t\t\t\t *  \treturn iTest;\n\t\t\t\t\t *  }\n\t\t\t\t\t * So basically we have a test for each column, and if that column matches, test the\n\t\t\t\t\t * next one. If all columns match, then we use a numeric sort on the position the two\n\t\t\t\t\t * row have in the original data array in order to provide a stable sort. In order to\n\t\t\t\t\t * get the position for the numeric stablisation, we need to take a clone of the current\n\t\t\t\t\t * display array and then get the position of the sorting value from that during the\n\t\t\t\t\t * sort.\n\t\t\t\t\t *\n\t\t\t\t\t * Note that for use with the Closure compiler, we need to be very careful how we deal \n\t\t\t\t\t * with this eval. Closure will rename all of our local variables, resutling in breakage\n\t\t\t\t\t * if the variables in the eval don't also reflect this. For this reason, we need to use\n\t\t\t\t\t * 'this' to store the variables we need in the eval, so we can control them. A little\n\t\t\t\t\t * nasty, but well worth it for using Closure.\n\t\t\t\t\t */\n\t\t\t\t\tthis.ClosureDataTables = {\n\t\t\t\t\t\t\"fn\": function(){},\n\t\t\t\t\t\t\"data\": aoData,\n\t\t\t\t\t\t\"sort\": _oExt.oSort,\n\t\t\t\t\t\t\"master\": oSettings.aiDisplayMaster.slice()\n\t\t\t\t\t};\n\t\t\t\t\tvar sDynamicSort = \"this.ClosureDataTables.fn = function(a,b){\"+\n\t\t\t\t\t\t\"var iTest, oSort=this.ClosureDataTables.sort, \"+\n\t\t\t\t\t\t\"aoData=this.ClosureDataTables.data, \"+\n\t\t\t\t\t\t\"aiOrig=this.ClosureDataTables.master;\";\n\t\t\t\t\t\n\t\t\t\t\tfor ( i=0 ; i<aaSort.length-1 ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tiDataSort = oSettings.aoColumns[ aaSort[i][0] ].iDataSort;\n\t\t\t\t\t\tiDataType = oSettings.aoColumns[ iDataSort ].sType;\n\t\t\t\t\t\tsDynamicSort += \"iTest = oSort['\"+iDataType+\"-\"+aaSort[i][1]+\"']\"+\n\t\t\t\t\t\t\t\"( aoData[a]._aData[\"+iDataSort+\"], aoData[b]._aData[\"+iDataSort+\"] ); if ( iTest === 0 )\";\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif ( aaSort.length > 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\tiDataSort = oSettings.aoColumns[ aaSort[aaSort.length-1][0] ].iDataSort;\n\t\t\t\t\t\tiDataType = oSettings.aoColumns[ iDataSort ].sType;\n\t\t\t\t\t\tsDynamicSort += \"iTest = oSort['\"+iDataType+\"-\"+aaSort[aaSort.length-1][1]+\"']\"+\n\t\t\t\t\t\t\t\"( aoData[a]._aData[\"+iDataSort+\"], aoData[b]._aData[\"+iDataSort+\"] );\"+\n\t\t\t\t\t\t\t\"if (iTest===0) \"+\n\t\t\t\t\t\t\t\t\"return oSort['numeric-asc'](jQuery.inArray(a,aiOrig), jQuery.inArray(b,aiOrig)); \"+\n\t\t\t\t\t\t\t\"return iTest;}\";\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* The eval has to be done to a variable for IE */\n\t\t\t\t\t\teval( sDynamicSort );\n\t\t\t\t\t\toSettings.aiDisplayMaster.sort( this.ClosureDataTables.fn );\n\t\t\t\t\t}\n\t\t\t\t\tthis.ClosureDataTables = undefined;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t/*\n\t\t\t\t\t * Non-eval() sorting (AIR and other environments which doesn't allow code in eval()\n\t\t\t\t\t * Note that for reasonable sized data sets this method is around 1.5 times slower than\n\t\t\t\t\t * the eval above (hence why it is not used all the time). Oddly enough, it is ever so\n\t\t\t\t\t * slightly faster for very small sets (presumably the eval has overhead).\n\t\t\t\t\t *   Single column (1083 records) - eval: 32mS   AIR: 38mS\n\t\t\t\t\t *   Two columns (1083 records) -   eval: 55mS   AIR: 66mS\n\t\t\t\t\t */\n\t\t\t\t\t\n\t\t\t\t\t/* Build a cached array so the sort doesn't have to process this stuff on every call */\n\t\t\t\t\tvar aAirSort = [];\n\t\t\t\t\tvar iLen = aaSort.length;\n\t\t\t\t\tfor ( i=0 ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tiDataSort = oSettings.aoColumns[ aaSort[i][0] ].iDataSort;\n\t\t\t\t\t\taAirSort.push( [\n\t\t\t\t\t\t\tiDataSort,\n\t\t\t\t\t\t\toSettings.aoColumns[ iDataSort ].sType+'-'+aaSort[i][1]\n\t\t\t\t\t\t] );\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\toSettings.aiDisplayMaster.sort( function (a,b) {\n\t\t\t\t\t\tvar iTest;\n\t\t\t\t\t\tfor ( var i=0 ; i<iLen ; i++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tiTest = oSort[ aAirSort[i][1] ]( aoData[a]._aData[aAirSort[i][0]], aoData[b]._aData[aAirSort[i][0]] );\n\t\t\t\t\t\t\tif ( iTest !== 0 )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn iTest;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Alter the sorting classes to take account of the changes */\n\t\t\tif ( typeof bApplyClasses == 'undefined' || bApplyClasses )\n\t\t\t{\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* Tell the draw function that we have sorted the data */\n\t\t\toSettings.bSorted = true;\n\t\t\t\n\t\t\t/* Copy the master data into the draw array and re-draw */\n\t\t\tif ( oSettings.oFeatures.bFilter )\n\t\t\t{\n\t\t\t\t/* _fnFilter() will redraw the table for us */\n\t\t\t\t_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\toSettings._iDisplayStart = 0; /* reset display back to page 0 */\n\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t_fnDraw( oSettings );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnSortAttachListener\n\t\t * Purpose:  Attach a sort handler (click) to a node\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           node:nNode - node to attach the handler to\n\t\t *           int:iDataIndex - column sorting index\n\t\t *           function:fnCallback - callback function - optional\n\t\t */\n\t\tfunction _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )\n\t\t{\n\t\t\t$(nNode).click( function (e) {\n\t\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\t\tif ( oSettings.aoColumns[iDataIndex].bSortable === false )\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/*\n\t\t\t\t * This is a little bit odd I admit... I declare a temporary function inside the scope of\n\t\t\t\t * _fnDrawHead and the click handler in order that the code presented here can be used \n\t\t\t\t * twice - once for when bProcessing is enabled, and another time for when it is \n\t\t\t\t * disabled, as we need to perform slightly different actions.\n\t\t\t\t *   Basically the issue here is that the Javascript engine in modern browsers don't \n\t\t\t\t * appear to allow the rendering engine to update the display while it is still excuting\n\t\t\t\t * it's thread (well - it does but only after long intervals). This means that the \n\t\t\t\t * 'processing' display doesn't appear for a table sort. To break the js thread up a bit\n\t\t\t\t * I force an execution break by using setTimeout - but this breaks the expected \n\t\t\t\t * thread continuation for the end-developer's point of view (their code would execute\n\t\t\t\t * too early), so we on;y do it when we absolutely have to.\n\t\t\t\t */\n\t\t\t\tvar fnInnerSorting = function () {\n\t\t\t\t\tvar iColumn, iNextSort;\n\t\t\t\t\t\n\t\t\t\t\t/* If the shift key is pressed then we are multipe column sorting */\n\t\t\t\t\tif ( e.shiftKey )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Are we already doing some kind of sort on this column? */\n\t\t\t\t\t\tvar bFound = false;\n\t\t\t\t\t\tfor ( var i=0 ; i<oSettings.aaSorting.length ; i++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( oSettings.aaSorting[i][0] == iDataIndex )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbFound = true;\n\t\t\t\t\t\t\t\tiColumn = oSettings.aaSorting[i][0];\n\t\t\t\t\t\t\t\tiNextSort = oSettings.aaSorting[i][2]+1;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ( typeof oSettings.aoColumns[iColumn].asSorting[iNextSort] == 'undefined' )\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t/* Reached the end of the sorting options, remove from multi-col sort */\n\t\t\t\t\t\t\t\t\toSettings.aaSorting.splice( i, 1 );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t/* Move onto next sorting direction */\n\t\t\t\t\t\t\t\t\toSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];\n\t\t\t\t\t\t\t\t\toSettings.aaSorting[i][2] = iNextSort;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* No sort yet - add it in */\n\t\t\t\t\t\tif ( bFound === false )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toSettings.aaSorting.push( [ iDataIndex, \n\t\t\t\t\t\t\t\toSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t/* If no shift key then single column sort */\n\t\t\t\t\t\tif ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tiColumn = oSettings.aaSorting[0][0];\n\t\t\t\t\t\t\tiNextSort = oSettings.aaSorting[0][2]+1;\n\t\t\t\t\t\t\tif ( typeof oSettings.aoColumns[iColumn].asSorting[iNextSort] == 'undefined' )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tiNextSort = 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\toSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];\n\t\t\t\t\t\t\toSettings.aaSorting[0][2] = iNextSort;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toSettings.aaSorting.splice( 0, oSettings.aaSorting.length );\n\t\t\t\t\t\t\toSettings.aaSorting.push( [ iDataIndex, \n\t\t\t\t\t\t\t\toSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t/* Run the sort */\n\t\t\t\t\t_fnSort( oSettings );\n\t\t\t\t}; /* /fnInnerSorting */\n\t\t\t\t\n\t\t\t\tif ( !oSettings.oFeatures.bProcessing )\n\t\t\t\t{\n\t\t\t\t\tfnInnerSorting();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_fnProcessingDisplay( oSettings, true );\n\t\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t\tfnInnerSorting();\n\t\t\t\t\t\tif ( !oSettings.oFeatures.bServerSide )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 0 );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Call the user specified callback function - used for async user interaction */\n\t\t\t\tif ( typeof fnCallback == 'function' )\n\t\t\t\t{\n\t\t\t\t\tfnCallback( oSettings );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnSortingClasses\n\t\t * Purpose:  Set the sortting classes on the header\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t * Notes:    It is safe to call this function when bSort and bSortClasses are false\n\t\t */\n\t\tfunction _fnSortingClasses( oSettings )\n\t\t{\n\t\t\tvar i, iLen, j, jLen, iFound;\n\t\t\tvar aaSort, sClass;\n\t\t\tvar iColumns = oSettings.aoColumns.length;\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\tfor ( i=0 ; i<iColumns ; i++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aoColumns[i].bSortable )\n\t\t\t\t{\n\t\t\t\t\t$(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +\" \"+ oClasses.sSortDesc +\n\t\t\t\t \t\t\" \"+ oSettings.aoColumns[i].sSortingClass );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif ( oSettings.aaSortingFixed !== null )\n\t\t\t{\n\t\t\t\taaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taaSort = oSettings.aaSorting.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the required classes to the header */\n\t\t\tfor ( i=0 ; i<oSettings.aoColumns.length ; i++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aoColumns[i].bSortable )\n\t\t\t\t{\n\t\t\t\t\tsClass = oSettings.aoColumns[i].sSortingClass;\n\t\t\t\t\tiFound = -1;\n\t\t\t\t\tfor ( j=0 ; j<aaSort.length ; j++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( aaSort[j][0] == i )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsClass = ( aaSort[j][1] == \"asc\" ) ?\n\t\t\t\t\t\t\t\toClasses.sSortAsc : oClasses.sSortDesc;\n\t\t\t\t\t\t\tiFound = j;\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\t$(oSettings.aoColumns[i].nTh).addClass( sClass );\n\t\t\t\t\t\n\t\t\t\t\tif ( oSettings.bJUI )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* jQuery UI uses extra markup */\n\t\t\t\t\t\tvar jqSpan = $(\"span\", oSettings.aoColumns[i].nTh);\n\t\t\t\t\t\tjqSpan.removeClass(oClasses.sSortJUIAsc +\" \"+ oClasses.sSortJUIDesc +\" \"+ \n\t\t\t\t\t\t\toClasses.sSortJUI +\" \"+ oClasses.sSortJUIAscAllowed +\" \"+ oClasses.sSortJUIDescAllowed );\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar sSpanClass;\n\t\t\t\t\t\tif ( iFound == -1 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t \tsSpanClass = oSettings.aoColumns[i].sSortingClassJUI;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( aaSort[iFound][1] == \"asc\" )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsSpanClass = oClasses.sSortJUIAsc;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsSpanClass = oClasses.sSortJUIDesc;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tjqSpan.addClass( sSpanClass );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t/* No sorting on this column, so add the base class. This will have been assigned by\n\t\t\t\t\t * _fnAddColumn\n\t\t\t\t\t */\n\t\t\t\t\t$(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* \n\t\t\t * Apply the required classes to the table body\n\t\t\t * Note that this is given as a feature switch since it can significantly slow down a sort\n\t\t\t * on large data sets (adding and removing of classes is always slow at the best of times..)\n\t\t\t * Further to this, note that this code is admitadly fairly ugly. It could be made a lot \n\t\t\t * simpiler using jQuery selectors and add/removeClass, but that is significantly slower\n\t\t\t * (on the order of 5 times slower) - hence the direct DOM manipulation here.\n\t\t\t */\n\t\t\tsClass = oClasses.sSortColumn;\n\t\t\t\n\t\t\tif ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )\n\t\t\t{\n\t\t\t\tvar nTds = _fnGetTdNodes( oSettings );\n\t\t\t\t\n\t\t\t\t/* Remove the old classes */\n\t\t\t\tif ( nTds.length >= iColumns )\n\t\t\t\t{\n\t\t\t\t\tfor ( i=0 ; i<iColumns ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( nTds[i].className.indexOf(sClass+\"1\") != -1 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnTds[(iColumns*j)+i].className = \n\t\t\t\t\t\t\t\t\t$.trim( nTds[(iColumns*j)+i].className.replace( sClass+\"1\", \"\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( nTds[i].className.indexOf(sClass+\"2\") != -1 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnTds[(iColumns*j)+i].className = \n\t\t\t\t\t\t\t\t\t$.trim( nTds[(iColumns*j)+i].className.replace( sClass+\"2\", \"\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( nTds[i].className.indexOf(sClass+\"3\") != -1 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnTds[(iColumns*j)+i].className = \n\t\t\t\t\t\t\t\t\t$.trim( nTds[(iColumns*j)+i].className.replace( \" \"+sClass+\"3\", \"\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Add the new classes to the table */\n\t\t\t\tvar iClass = 1, iTargetCol;\n\t\t\t\tfor ( i=0 ; i<aaSort.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\tiTargetCol = parseInt( aaSort[i][0], 10 );\n\t\t\t\t\tfor ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTds[(iColumns*j)+iTargetCol].className += \" \"+sClass+iClass;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif ( iClass < 3 )\n\t\t\t\t\t{\n\t\t\t\t\t\tiClass++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Feature: Pagination. Note that most of the paging logic is done in \n\t\t * _oExt.oPagination\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnFeatureHtmlPaginate\n\t\t * Purpose:  Generate the node required for default pagination\n\t\t * Returns:  node\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnFeatureHtmlPaginate ( oSettings )\n\t\t{\n\t\t\tif ( oSettings.oScroll.bInfinite )\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\tvar nPaginate = document.createElement( 'div' );\n\t\t\tnPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;\n\t\t\t\n\t\t\t_oExt.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, \n\t\t\t\tfunction( oSettings ) {\n\t\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t\t_fnDraw( oSettings );\n\t\t\t\t}\n\t\t\t);\n\t\t\t\n\t\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\t\tif ( typeof oSettings.aanFeatures.p == \"undefined\" )\n\t\t\t{\n\t\t\t\toSettings.aoDrawCallback.push( {\n\t\t\t\t\t\"fn\": function( oSettings ) {\n\t\t\t\t\t\t_oExt.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {\n\t\t\t\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t\t\t\t_fnDraw( oSettings );\n\t\t\t\t\t\t} );\n\t\t\t\t\t},\n\t\t\t\t\t\"sName\": \"pagination\"\n\t\t\t\t} );\n\t\t\t}\n\t\t\treturn nPaginate;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnPageChange\n\t\t * Purpose:  Alter the display settings to change the page\n\t\t * Returns:  bool:true - page has changed, false - no change (no effect) eg 'first' on page 1\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           string:sAction - paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t */\n\t\tfunction _fnPageChange ( oSettings, sAction )\n\t\t{\n\t\t\tvar iOldStart = oSettings._iDisplayStart;\n\t\t\t\n\t\t\tif ( sAction == \"first\" )\n\t\t\t{\n\t\t\t\toSettings._iDisplayStart = 0;\n\t\t\t}\n\t\t\telse if ( sAction == \"previous\" )\n\t\t\t{\n\t\t\t\toSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?\n\t\t\t\t\toSettings._iDisplayStart - oSettings._iDisplayLength :\n\t\t\t\t\t0;\n\t\t\t\t\n\t\t\t\t/* Correct for underrun */\n\t\t\t\tif ( oSettings._iDisplayStart < 0 )\n\t\t\t\t{\n\t\t\t\t  oSettings._iDisplayStart = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( sAction == \"next\" )\n\t\t\t{\n\t\t\t\tif ( oSettings._iDisplayLength >= 0 )\n\t\t\t\t{\n\t\t\t\t\t/* Make sure we are not over running the display array */\n\t\t\t\t\tif ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings._iDisplayStart += oSettings._iDisplayLength;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\toSettings._iDisplayStart = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( sAction == \"last\" )\n\t\t\t{\n\t\t\t\tif ( oSettings._iDisplayLength >= 0 )\n\t\t\t\t{\n\t\t\t\t\tvar iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;\n\t\t\t\t\toSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\toSettings._iDisplayStart = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_fnLog( oSettings, 0, \"Unknown paging action: \"+sAction );\n\t\t\t}\n\t\t\t\n\t\t\treturn iOldStart != oSettings._iDisplayStart;\n\t\t}\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Feature: HTML info\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnFeatureHtmlInfo\n\t\t * Purpose:  Generate the node required for the info display\n\t\t * Returns:  node\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnFeatureHtmlInfo ( oSettings )\n\t\t{\n\t\t\tvar nInfo = document.createElement( 'div' );\n\t\t\tnInfo.className = oSettings.oClasses.sInfo;\n\t\t\t\n\t\t\t/* Actions that are to be taken once only for this feature */\n\t\t\tif ( typeof oSettings.aanFeatures.i == \"undefined\" )\n\t\t\t{\n\t\t\t\t/* Add draw callback */\n\t\t\t\toSettings.aoDrawCallback.push( {\n\t\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\t\"sName\": \"information\"\n\t\t\t\t} );\n\t\t\t\t\n\t\t\t\t/* Add id */\n\t\t\t\tif ( oSettings.sTableId !== '' )\n\t\t\t\t{\n\t\t\t\t\tnInfo.setAttribute( 'id', oSettings.sTableId+'_info' );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn nInfo;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnUpdateInfo\n\t\t * Purpose:  Update the information elements in the display\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnUpdateInfo ( oSettings )\n\t\t{\n\t\t\t/* Show information about the table */\n\t\t\tif ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar\n\t\t\t\tiStart = oSettings._iDisplayStart+1, iEnd = oSettings.fnDisplayEnd(),\n\t\t\t\tiMax = oSettings.fnRecordsTotal(), iTotal = oSettings.fnRecordsDisplay(),\n\t\t\t\tsStart = oSettings.fnFormatNumber( iStart ), sEnd = oSettings.fnFormatNumber( iEnd ),\n\t\t\t\tsMax = oSettings.fnFormatNumber( iMax ), sTotal = oSettings.fnFormatNumber( iTotal ),\n\t\t\t\tsOut;\n\t\t\t\n\t\t\t/* When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t\t * internally\n\t\t\t */\n\t\t\tif ( oSettings.oScroll.bInfinite )\n\t\t\t{\n\t\t\t\tsStart = oSettings.fnFormatNumber( 1 );\n\t\t\t}\n\t\t\t\n\t\t\tif ( oSettings.fnRecordsDisplay() === 0 && \n\t\t\t\t   oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )\n\t\t\t{\n\t\t\t\t/* Empty record set */\n\t\t\t\tsOut = oSettings.oLanguage.sInfoEmpty+ oSettings.oLanguage.sInfoPostFix;\n\t\t\t}\n\t\t\telse if ( oSettings.fnRecordsDisplay() === 0 )\n\t\t\t{\n\t\t\t\t/* Rmpty record set after filtering */\n\t\t\t\tsOut = oSettings.oLanguage.sInfoEmpty +' '+ \n\t\t\t\t\toSettings.oLanguage.sInfoFiltered.replace('_MAX_', sMax)+\n\t\t\t\t\t\toSettings.oLanguage.sInfoPostFix;\n\t\t\t}\n\t\t\telse if ( oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )\n\t\t\t{\n\t\t\t\t/* Normal record set */\n\t\t\t\tsOut = oSettings.oLanguage.sInfo.\n\t\t\t\t\t\treplace('_START_', sStart).\n\t\t\t\t\t\treplace('_END_',   sEnd).\n\t\t\t\t\t\treplace('_TOTAL_', sTotal)+ \n\t\t\t\t\toSettings.oLanguage.sInfoPostFix;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Record set after filtering */\n\t\t\t\tsOut = oSettings.oLanguage.sInfo.\n\t\t\t\t\t\treplace('_START_', sStart).\n\t\t\t\t\t\treplace('_END_',   sEnd).\n\t\t\t\t\t\treplace('_TOTAL_', sTotal) +' '+ \n\t\t\t\t\toSettings.oLanguage.sInfoFiltered.replace('_MAX_', \n\t\t\t\t\t\toSettings.fnFormatNumber(oSettings.fnRecordsTotal()))+ \n\t\t\t\t\toSettings.oLanguage.sInfoPostFix;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oSettings.oLanguage.fnInfoCallback !== null )\n\t\t\t{\n\t\t\t\tsOut = oSettings.oLanguage.fnInfoCallback( oSettings, iStart, iEnd, iMax, iTotal, sOut );\n\t\t\t}\n\t\t\t\n\t\t\tvar n = oSettings.aanFeatures.i;\n\t\t\tfor ( var i=0, iLen=n.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t$(n[i]).html( sOut );\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Feature: Length change\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnFeatureHtmlLength\n\t\t * Purpose:  Generate the node required for user display length changing\n\t\t * Returns:  node\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnFeatureHtmlLength ( oSettings )\n\t\t{\n\t\t\tif ( oSettings.oScroll.bInfinite )\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t\t/* This can be overruled by not using the _MENU_ var/macro in the language variable */\n\t\t\tvar sName = (oSettings.sTableId === \"\") ? \"\" : 'name=\"'+oSettings.sTableId+'_length\"';\n\t\t\tvar sStdMenu = '<select size=\"1\" '+sName+'>';\n\t\t\tvar i, iLen;\n\t\t\t\n\t\t\tif ( oSettings.aLengthMenu.length == 2 && typeof oSettings.aLengthMenu[0] == 'object' && \n\t\t\t\t\ttypeof oSettings.aLengthMenu[1] == 'object' )\n\t\t\t{\n\t\t\t\tfor ( i=0, iLen=oSettings.aLengthMenu[0].length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tsStdMenu += '<option value=\"'+oSettings.aLengthMenu[0][i]+'\">'+\n\t\t\t\t\t\toSettings.aLengthMenu[1][i]+'</option>';\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor ( i=0, iLen=oSettings.aLengthMenu.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tsStdMenu += '<option value=\"'+oSettings.aLengthMenu[i]+'\">'+\n\t\t\t\t\t\toSettings.aLengthMenu[i]+'</option>';\n\t\t\t\t}\n\t\t\t}\n\t\t\tsStdMenu += '</select>';\n\t\t\t\n\t\t\tvar nLength = document.createElement( 'div' );\n\t\t\tif ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.l == \"undefined\" )\n\t\t\t{\n\t\t\t\tnLength.setAttribute( 'id', oSettings.sTableId+'_length' );\n\t\t\t}\n\t\t\tnLength.className = oSettings.oClasses.sLength;\n\t\t\tnLength.innerHTML = oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu );\n\t\t\t\n\t\t\t/*\n\t\t\t * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,\n\t\t\t * and Stefan Skopnik for fixing the fix!\n\t\t\t */\n\t\t\t$('select option[value=\"'+oSettings._iDisplayLength+'\"]',nLength).attr(\"selected\",true);\n\t\t\t\n\t\t\t$('select', nLength).change( function(e) {\n\t\t\t\tvar iVal = $(this).val();\n\t\t\t\t\n\t\t\t\t/* Update all other length options for the new display */\n\t\t\t\tvar n = oSettings.aanFeatures.l;\n\t\t\t\tfor ( i=0, iLen=n.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( n[i] != this.parentNode )\n\t\t\t\t\t{\n\t\t\t\t\t\t$('select', n[i]).val( iVal );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Redraw the table */\n\t\t\t\toSettings._iDisplayLength = parseInt(iVal, 10);\n\t\t\t\t_fnCalculateEnd( oSettings );\n\t\t\t\t\n\t\t\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\t\t\tif ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )\n\t\t\t\t{\n\t\t\t\t\toSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;\n\t\t\t\t\tif ( oSettings._iDisplayStart < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings._iDisplayStart = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( oSettings._iDisplayLength == -1 )\n\t\t\t\t{\n\t\t\t\t\toSettings._iDisplayStart = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t_fnDraw( oSettings );\n\t\t\t} );\n\t\t\t\n\t\t\treturn nLength;\n\t\t}\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Feature: Processing incidator\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnFeatureHtmlProcessing\n\t\t * Purpose:  Generate the node required for the processing node\n\t\t * Returns:  node\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnFeatureHtmlProcessing ( oSettings )\n\t\t{\n\t\t\tvar nProcessing = document.createElement( 'div' );\n\t\t\t\n\t\t\tif ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.r == \"undefined\" )\n\t\t\t{\n\t\t\t\tnProcessing.setAttribute( 'id', oSettings.sTableId+'_processing' );\n\t\t\t}\n\t\t\tnProcessing.innerHTML = oSettings.oLanguage.sProcessing;\n\t\t\tnProcessing.className = oSettings.oClasses.sProcessing;\n\t\t\toSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );\n\t\t\t\n\t\t\treturn nProcessing;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnProcessingDisplay\n\t\t * Purpose:  Display or hide the processing indicator\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           bool:\n\t\t *   true - show the processing indicator\n\t\t *   false - don't show\n\t\t */\n\t\tfunction _fnProcessingDisplay ( oSettings, bShow )\n\t\t{\n\t\t\tif ( oSettings.oFeatures.bProcessing )\n\t\t\t{\n\t\t\t\tvar an = oSettings.aanFeatures.r;\n\t\t\t\tfor ( var i=0, iLen=an.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tan[i].style.visibility = bShow ? \"visible\" : \"hidden\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Support functions\n\t\t */\n\t\t\n\t\t/*\n\t\t * Function: _fnVisibleToColumnIndex\n\t\t * Purpose:  Covert the index of a visible column to the index in the data array (take account\n\t\t *   of hidden columns)\n\t\t * Returns:  int:i - the data index\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t\t{\n\t\t\tvar iColumn = -1;\n\t\t\t\n\t\t\tfor ( var i=0 ; i<oSettings.aoColumns.length ; i++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aoColumns[i].bVisible === true )\n\t\t\t\t{\n\t\t\t\t\tiColumn++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( iColumn == iMatch )\n\t\t\t\t{\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnColumnIndexToVisible\n\t\t * Purpose:  Covert the index of an index in the data array and convert it to the visible\n\t\t *   column index (take account of hidden columns)\n\t\t * Returns:  int:i - the data index\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t\t{\n\t\t\tvar iVisible = -1;\n\t\t\tfor ( var i=0 ; i<oSettings.aoColumns.length ; i++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aoColumns[i].bVisible === true )\n\t\t\t\t{\n\t\t\t\t\tiVisible++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( i == iMatch )\n\t\t\t\t{\n\t\t\t\t\treturn oSettings.aoColumns[i].bVisible === true ? iVisible : null;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\t\n\t\t/*\n\t\t * Function: _fnNodeToDataIndex\n\t\t * Purpose:  Take a TR element and convert it to an index in aoData\n\t\t * Returns:  int:i - index if found, null if not\n\t\t * Inputs:   object:s - dataTables settings object\n\t\t *           node:n - the TR element to find\n\t\t */\n\t\tfunction _fnNodeToDataIndex( s, n )\n\t\t{\n\t\t\tvar i, iLen;\n\t\t\t\n\t\t\t/* Optimisation - see if the nodes which are currently visible match, since that is\n\t\t\t * the most likely node to be asked for (a selector or event for example)\n\t\t\t */\n\t\t\tfor ( i=s._iDisplayStart, iLen=s._iDisplayEnd ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tif ( s.aoData[ s.aiDisplay[i] ].nTr == n )\n\t\t\t\t{\n\t\t\t\t\treturn s.aiDisplay[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Otherwise we are in for a slog through the whole data cache */\n\t\t\tfor ( i=0, iLen=s.aoData.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tif ( s.aoData[i].nTr == n )\n\t\t\t\t{\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnVisbleColumns\n\t\t * Purpose:  Get the number of visible columns\n\t\t * Returns:  int:i - the number of visible columns\n\t\t * Inputs:   object:oS - dataTables settings object\n\t\t */\n\t\tfunction _fnVisbleColumns( oS )\n\t\t{\n\t\t\tvar iVis = 0;\n\t\t\tfor ( var i=0 ; i<oS.aoColumns.length ; i++ )\n\t\t\t{\n\t\t\t\tif ( oS.aoColumns[i].bVisible === true )\n\t\t\t\t{\n\t\t\t\t\tiVis++;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn iVis;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnCalculateEnd\n\t\t * Purpose:  Rcalculate the end point based on the start point\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnCalculateEnd( oSettings )\n\t\t{\n\t\t\tif ( oSettings.oFeatures.bPaginate === false )\n\t\t\t{\n\t\t\t\toSettings._iDisplayEnd = oSettings.aiDisplay.length;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Set the end point of the display - based on how many elements there are\n\t\t\t\t * still to display\n\t\t\t\t */\n\t\t\t\tif ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||\n\t\t\t\t\t   oSettings._iDisplayLength == -1 )\n\t\t\t\t{\n\t\t\t\t\toSettings._iDisplayEnd = oSettings.aiDisplay.length;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\toSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnConvertToWidth\n\t\t * Purpose:  Convert a CSS unit width to pixels (e.g. 2em)\n\t\t * Returns:  int:iWidth - width in pixels\n\t\t * Inputs:   string:sWidth - width to be converted\n\t\t *           node:nParent - parent to get the with for (required for\n\t\t *             relative widths) - optional\n\t\t */\n\t\tfunction _fnConvertToWidth ( sWidth, nParent )\n\t\t{\n\t\t\tif ( !sWidth || sWidth === null || sWidth === '' )\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t\n\t\t\tif ( typeof nParent == \"undefined\" )\n\t\t\t{\n\t\t\t\tnParent = document.getElementsByTagName('body')[0];\n\t\t\t}\n\t\t\t\n\t\t\tvar iWidth;\n\t\t\tvar nTmp = document.createElement( \"div\" );\n\t\t\tnTmp.style.width = sWidth;\n\t\t\t\n\t\t\tnParent.appendChild( nTmp );\n\t\t\tiWidth = nTmp.offsetWidth;\n\t\t\tnParent.removeChild( nTmp );\n\t\t\t\n\t\t\treturn ( iWidth );\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnCalculateColumnWidths\n\t\t * Purpose:  Calculate the width of columns for the table\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnCalculateColumnWidths ( oSettings )\n\t\t{\n\t\t\tvar iTableWidth = oSettings.nTable.offsetWidth;\n\t\t\tvar iUserInputs = 0;\n\t\t\tvar iTmpWidth;\n\t\t\tvar iVisibleColumns = 0;\n\t\t\tvar iColums = oSettings.aoColumns.length;\n\t\t\tvar i;\n\t\t\tvar oHeaders = $('th', oSettings.nTHead);\n\t\t\t\n\t\t\t/* Convert any user input sizes into pixel sizes */\n\t\t\tfor ( i=0 ; i<iColums ; i++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aoColumns[i].bVisible )\n\t\t\t\t{\n\t\t\t\t\tiVisibleColumns++;\n\t\t\t\t\t\n\t\t\t\t\tif ( oSettings.aoColumns[i].sWidth !== null )\n\t\t\t\t\t{\n\t\t\t\t\t\tiTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig, \n\t\t\t\t\t\t\toSettings.nTable.parentNode );\n\t\t\t\t\t\tif ( iTmpWidth !== null )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tiUserInputs++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* If the number of columns in the DOM equals the number that we have to process in \n\t\t\t * DataTables, then we can use the offsets that are created by the web-browser. No custom \n\t\t\t * sizes can be set in order for this to happen, nor scrolling used\n\t\t\t */\n\t\t\tif ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&\n\t\t\t\toSettings.oScroll.sX === \"\" && oSettings.oScroll.sY === \"\" )\n\t\t\t{\n\t\t\t\tfor ( i=0 ; i<oSettings.aoColumns.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\tiTmpWidth = $(oHeaders[i]).width();\n\t\t\t\t\tif ( iTmpWidth !== null )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Otherwise we are going to have to do some calculations to get the width of each column.\n\t\t\t\t * Construct a 1 row table with the widest node in the data, and any user defined widths,\n\t\t\t\t * then insert it into the DOM and allow the browser to do all the hard work of\n\t\t\t\t * calculating table widths.\n\t\t\t\t */\n\t\t\t\tvar\n\t\t\t\t\tnCalcTmp = oSettings.nTable.cloneNode( false ),\n\t\t\t\t\tnBody = document.createElement( 'tbody' ),\n\t\t\t\t\tnTr = document.createElement( 'tr' ),\n\t\t\t\t\tnDivSizing;\n\t\t\t\t\n\t\t\t\tnCalcTmp.removeAttribute( \"id\" );\n\t\t\t\tnCalcTmp.appendChild( oSettings.nTHead.cloneNode(true) );\n\t\t\t\tif ( oSettings.nTFoot !== null )\n\t\t\t\t{\n\t\t\t\t\tnCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );\n\t\t\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\t\t\tn.style.width = \"\";\n\t\t\t\t\t}, nCalcTmp.getElementsByTagName('tr') );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tnCalcTmp.appendChild( nBody );\n\t\t\t\tnBody.appendChild( nTr );\n\t\t\t\t\n\t\t\t\t/* Remove any sizing that was previously applied by the styles */\n\t\t\t\tvar jqColSizing = $('thead th', nCalcTmp);\n\t\t\t\tif ( jqColSizing.length === 0 )\n\t\t\t\t{\n\t\t\t\t\tjqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);\n\t\t\t\t}\n\t\t\t\tjqColSizing.each( function (i) {\n\t\t\t\t\tthis.style.width = \"\";\n\t\t\t\t\t\n\t\t\t\t\tvar iIndex = _fnVisibleToColumnIndex( oSettings, i );\n\t\t\t\t\tif ( iIndex !== null && oSettings.aoColumns[iIndex].sWidthOrig !== \"\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.style.width = oSettings.aoColumns[iIndex].sWidthOrig;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\t\n\t\t\t\t/* Find the biggest td for each column and put it into the table */\n\t\t\t\tfor ( i=0 ; i<iColums ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( oSettings.aoColumns[i].bVisible )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar nTd = _fnGetWidestNode( oSettings, i );\n\t\t\t\t\t\tif ( nTd !== null )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnTd = nTd.cloneNode(true);\n\t\t\t\t\t\t\tnTr.appendChild( nTd );\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\t/* Build the table and 'display' it */\n\t\t\t\tvar nWrapper = oSettings.nTable.parentNode;\n\t\t\t\tnWrapper.appendChild( nCalcTmp );\n\t\t\t\t\n\t\t\t\t/* When scrolling (X or Y) we want to set the width of the table as appropriate. However,\n\t\t\t\t * when not scrolling leave the table width as it is. This results in slightly different,\n\t\t\t\t * but I think correct behaviour\n\t\t\t\t */\n\t\t\t\tif ( oSettings.oScroll.sX !== \"\" && oSettings.oScroll.sXInner !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tnCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.oScroll.sX !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tnCalcTmp.style.width = \"\";\n\t\t\t\t\tif ( $(nCalcTmp).width() < nWrapper.offsetWidth )\n\t\t\t\t\t{\n\t\t\t\t\t\tnCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.oScroll.sY !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tnCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );\n\t\t\t\t}\n\t\t\t\tnCalcTmp.style.visibility = \"hidden\";\n\t\t\t\t\n\t\t\t\t/* Scrolling considerations */\n\t\t\t\t_fnScrollingWidthAdjust( oSettings, nCalcTmp );\n\t\t\t\t\n\t\t\t\t/* Read the width's calculated by the browser and store them for use by the caller. We\n\t\t\t\t * first of all try to use the elements in the body, but it is possible that there are\n\t\t\t\t * no elements there, under which circumstances we use the header elements\n\t\t\t\t */\n\t\t\t\tvar oNodes = $(\"tbody tr:eq(0)>td\", nCalcTmp);\n\t\t\t\tif ( oNodes.length === 0 )\n\t\t\t\t{\n\t\t\t\t\toNodes = $(\"thead tr:eq(0)>th\", nCalcTmp);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tvar iIndex, iCorrector = 0, iWidth;\n\t\t\t\tfor ( i=0 ; i<oSettings.aoColumns.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( oSettings.aoColumns[i].bVisible )\n\t\t\t\t\t{\n\t\t\t\t\t\tiWidth = $(oNodes[iCorrector]).width();\n\t\t\t\t\t\tif ( iWidth !== null && iWidth > 0 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiCorrector++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\toSettings.nTable.style.width = _fnStringToCss( $(nCalcTmp).outerWidth() );\n\t\t\t\tnCalcTmp.parentNode.removeChild( nCalcTmp );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnScrollingWidthAdjust\n\t\t * Purpose:  Adjust a table's width to take account of scrolling\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           node:n - table node\n\t\t */\n\t\tfunction _fnScrollingWidthAdjust ( oSettings, n )\n\t\t{\n\t\t\tif ( oSettings.oScroll.sX === \"\" && oSettings.oScroll.sY !== \"\" )\n\t\t\t{\n\t\t\t\t/* When y-scrolling only, we want to remove the width of the scroll bar so the table\n\t\t\t\t * + scroll bar will fit into the area avaialble.\n\t\t\t\t */\n\t\t\t\tvar iOrigWidth = $(n).width();\n\t\t\t\tn.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );\n\t\t\t}\n\t\t\telse if ( oSettings.oScroll.sX !== \"\" )\n\t\t\t{\n\t\t\t\t/* When x-scrolling both ways, fix the table at it's current size, without adjusting */\n\t\t\t\tn.style.width = _fnStringToCss( $(n).outerWidth() );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnGetWidestNode\n\t\t * Purpose:  Get the widest node\n\t\t * Returns:  string: - max strlens for each column\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           int:iCol - column of interest\n\t\t *           boolean:bFast - Should we use fast (but non-accurate) calculation - optional,\n\t\t *             default true\n\t\t * Notes:    This operation is _expensive_ (!!!). It requires a lot of DOM interaction, but\n\t\t *   this is the only way to reliably get the widest string. For example 'mmm' would be wider\n\t\t *   than 'iiii' so we can't just ocunt characters. If this can be optimised it would be good\n\t\t *   to do so!\n\t\t */\n\t\tfunction _fnGetWidestNode( oSettings, iCol, bFast )\n\t\t{\n\t\t\t/* Use fast not non-accurate calculate based on the strlen */\n\t\t\tif ( typeof bFast == 'undefined' || bFast )\n\t\t\t{\n\t\t\t\tvar iMaxLen = _fnGetMaxLenString( oSettings, iCol );\n\t\t\t\tvar iFastVis = _fnColumnIndexToVisible( oSettings, iCol);\n\t\t\t\tif ( iMaxLen < 0 )\n\t\t\t\t{\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\treturn oSettings.aoData[iMaxLen].nTr.getElementsByTagName('td')[iFastVis];\n\t\t\t}\n\t\t\t\n\t\t\t/* Use the slow approach, but get high quality answers - note that this code is not actually\n\t\t\t * used by DataTables by default. If you want to use it you can alter the call to \n\t\t\t * _fnGetWidestNode to pass 'false' as the third argument\n\t\t\t */\n\t\t\tvar\n\t\t\t\tiMax = -1, i, iLen,\n\t\t\t\tiMaxIndex = -1,\n\t\t\t\tn = document.createElement('div');\n\t\t\t\n\t\t\tn.style.visibility = \"hidden\";\n\t\t\tn.style.position = \"absolute\";\n\t\t\tdocument.body.appendChild( n );\n\t\t\t\n\t\t\tfor ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tn.innerHTML = oSettings.aoData[i]._aData[iCol];\n\t\t\t\tif ( n.offsetWidth > iMax )\n\t\t\t\t{\n\t\t\t\t\tiMax = n.offsetWidth;\n\t\t\t\t\tiMaxIndex = i;\n\t\t\t\t}\n\t\t\t}\n\t\t\tdocument.body.removeChild( n );\n\t\t\t\n\t\t\tif ( iMaxIndex >= 0 )\n\t\t\t{\n\t\t\t\tvar iVis = _fnColumnIndexToVisible( oSettings, iCol);\n\t\t\t\tvar nRet = oSettings.aoData[iMaxIndex].nTr.getElementsByTagName('td')[iVis];\n\t\t\t\tif ( nRet )\n\t\t\t\t{\n\t\t\t\t\treturn nRet;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnGetMaxLenString\n\t\t * Purpose:  Get the maximum strlen for each data column\n\t\t * Returns:  string: - max strlens for each column\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           int:iCol - column of interest\n\t\t */\n\t\tfunction _fnGetMaxLenString( oSettings, iCol )\n\t\t{\n\t\t\tvar iMax = -1;\n\t\t\tvar iMaxIndex = -1;\n\t\t\t\n\t\t\tfor ( var i=0 ; i<oSettings.aoData.length ; i++ )\n\t\t\t{\n\t\t\t\tvar s = oSettings.aoData[i]._aData[iCol];\n\t\t\t\tif ( s.length > iMax )\n\t\t\t\t{\n\t\t\t\t\tiMax = s.length;\n\t\t\t\t\tiMaxIndex = i;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn iMaxIndex;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnStringToCss\n\t\t * Purpose:  Append a CSS unit (only if required) to a string\n\t\t * Returns:  0 if match, 1 if length is different, 2 if no match\n\t\t * Inputs:   array:aArray1 - first array\n\t\t *           array:aArray2 - second array\n\t\t */\n\t\tfunction _fnStringToCss( s )\n\t\t{\n\t\t\tif ( s === null )\n\t\t\t{\n\t\t\t\treturn \"0px\";\n\t\t\t}\n\t\t\t\n\t\t\tif ( typeof s == 'number' )\n\t\t\t{\n\t\t\t\tif ( s < 0 )\n\t\t\t\t{\n\t\t\t\t\treturn \"0px\";\n\t\t\t\t}\n\t\t\t\treturn s+\"px\";\n\t\t\t}\n\t\t\t\n\t\t\t/* Check if the last character is not 0-9 */\n\t\t\tvar c = s.charCodeAt( s.length-1 );\n\t\t\tif (c < 0x30 || c > 0x39)\n\t\t\t{\n\t\t\t\treturn s;\n\t\t\t}\n\t\t\treturn s+\"px\";\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnArrayCmp\n\t\t * Purpose:  Compare two arrays\n\t\t * Returns:  0 if match, 1 if length is different, 2 if no match\n\t\t * Inputs:   array:aArray1 - first array\n\t\t *           array:aArray2 - second array\n\t\t */\n\t\tfunction _fnArrayCmp( aArray1, aArray2 )\n\t\t{\n\t\t\tif ( aArray1.length != aArray2.length )\n\t\t\t{\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\t\n\t\t\tfor ( var i=0 ; i<aArray1.length ; i++ )\n\t\t\t{\n\t\t\t\tif ( aArray1[i] != aArray2[i] )\n\t\t\t\t{\n\t\t\t\t\treturn 2;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn 0;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnDetectType\n\t\t * Purpose:  Get the sort type based on an input string\n\t\t * Returns:  string: - type (defaults to 'string' if no type can be detected)\n\t\t * Inputs:   string:sData - data we wish to know the type of\n\t\t * Notes:    This function makes use of the DataTables plugin objct _oExt \n\t\t *   (.aTypes) such that new types can easily be added.\n\t\t */\n\t\tfunction _fnDetectType( sData )\n\t\t{\n\t\t\tvar aTypes = _oExt.aTypes;\n\t\t\tvar iLen = aTypes.length;\n\t\t\t\n\t\t\tfor ( var i=0 ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar sType = aTypes[i]( sData );\n\t\t\t\tif ( sType !== null )\n\t\t\t\t{\n\t\t\t\t\treturn sType;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn 'string';\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnSettingsFromNode\n\t\t * Purpose:  Return the settings object for a particular table\n\t\t * Returns:  object: Settings object - or null if not found\n\t\t * Inputs:   node:nTable - table we are using as a dataTable\n\t\t */\n\t\tfunction _fnSettingsFromNode ( nTable )\n\t\t{\n\t\t\tfor ( var i=0 ; i<_aoSettings.length ; i++ )\n\t\t\t{\n\t\t\t\tif ( _aoSettings[i].nTable == nTable )\n\t\t\t\t{\n\t\t\t\t\treturn _aoSettings[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnGetDataMaster\n\t\t * Purpose:  Return an array with the full table data\n\t\t * Returns:  array array:aData - Master data array\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnGetDataMaster ( oSettings )\n\t\t{\n\t\t\tvar aData = [];\n\t\t\tvar iLen = oSettings.aoData.length;\n\t\t\tfor ( var i=0 ; i<iLen; i++ )\n\t\t\t{\n\t\t\t\taData.push( oSettings.aoData[i]._aData );\n\t\t\t}\n\t\t\treturn aData;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnGetTrNodes\n\t\t * Purpose:  Return an array with the TR nodes for the table\n\t\t * Returns:  array: - TR array\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnGetTrNodes ( oSettings )\n\t\t{\n\t\t\tvar aNodes = [];\n\t\t\tvar iLen = oSettings.aoData.length;\n\t\t\tfor ( var i=0 ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\taNodes.push( oSettings.aoData[i].nTr );\n\t\t\t}\n\t\t\treturn aNodes;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnGetTdNodes\n\t\t * Purpose:  Return an array with the TD nodes for the table\n\t\t * Returns:  array: - TD array\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnGetTdNodes ( oSettings )\n\t\t{\n\t\t\tvar nTrs = _fnGetTrNodes( oSettings );\n\t\t\tvar nTds = [], nTd;\n\t\t\tvar anReturn = [];\n\t\t\tvar iCorrector;\n\t\t\tvar iRow, iRows, iColumn, iColumns;\n\t\t\t\n\t\t\tfor ( iRow=0, iRows=nTrs.length ; iRow<iRows ; iRow++ )\n\t\t\t{\n\t\t\t\tnTds = [];\n\t\t\t\tfor ( iColumn=0, iColumns=nTrs[iRow].childNodes.length ; iColumn<iColumns ; iColumn++ )\n\t\t\t\t{\n\t\t\t\t\tnTd = nTrs[iRow].childNodes[iColumn];\n\t\t\t\t\tif ( nTd.nodeName.toUpperCase() == \"TD\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTds.push( nTd );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tiCorrector = 0;\n\t\t\t\tfor ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )\n\t\t\t\t{\n\t\t\t\t\tif ( oSettings.aoColumns[iColumn].bVisible )\n\t\t\t\t\t{\n\t\t\t\t\t\tanReturn.push( nTds[iColumn-iCorrector] );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tanReturn.push( oSettings.aoData[iRow]._anHidden[iColumn] );\n\t\t\t\t\t\tiCorrector++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn anReturn;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnEscapeRegex\n\t\t * Purpose:  scape a string stuch that it can be used in a regular expression\n\t\t * Returns:  string: - escaped string\n\t\t * Inputs:   string:sVal - string to escape\n\t\t */\n\t\tfunction _fnEscapeRegex ( sVal )\n\t\t{\n\t\t\tvar acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^' ];\n\t\t  var reReplace = new RegExp( '(\\\\' + acEscape.join('|\\\\') + ')', 'g' );\n\t\t  return sVal.replace(reReplace, '\\\\$1');\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnDeleteIndex\n\t\t * Purpose:  Take an array of integers (index array) and remove a target integer (value - not \n\t\t *             the key!)\n\t\t * Returns:  -\n\t\t * Inputs:   a:array int - Index array to target\n\t\t *           int:iTarget - value to find\n\t\t */\n\t\tfunction _fnDeleteIndex( a, iTarget )\n\t\t{\n\t\t\tvar iTargetIndex = -1;\n\t\t\t\n\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tif ( a[i] == iTarget )\n\t\t\t\t{\n\t\t\t\t\tiTargetIndex = i;\n\t\t\t\t}\n\t\t\t\telse if ( a[i] > iTarget )\n\t\t\t\t{\n\t\t\t\t\ta[i]--;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif ( iTargetIndex != -1 )\n\t\t\t{\n\t\t\t\ta.splice( iTargetIndex, 1 );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnReOrderIndex\n\t\t * Purpose:  Figure out how to reorder a display list\n\t\t * Returns:  array int:aiReturn - index list for reordering\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnReOrderIndex ( oSettings, sColumns )\n\t\t{\n\t\t\tvar aColumns = sColumns.split(',');\n\t\t\tvar aiReturn = [];\n\t\t\t\n\t\t\tfor ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfor ( var j=0 ; j<iLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( oSettings.aoColumns[i].sName == aColumns[j] )\n\t\t\t\t\t{\n\t\t\t\t\t\taiReturn.push( j );\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\t\n\t\t\treturn aiReturn;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnColumnOrdering\n\t\t * Purpose:  Get the column ordering that DataTables expects\n\t\t * Returns:  string: - comma separated list of names\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnColumnOrdering ( oSettings )\n\t\t{\n\t\t\tvar sNames = '';\n\t\t\tfor ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tsNames += oSettings.aoColumns[i].sName+',';\n\t\t\t}\n\t\t\tif ( sNames.length == iLen )\n\t\t\t{\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\treturn sNames.slice(0, -1);\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnLog\n\t\t * Purpose:  Log an error message\n\t\t * Returns:  -\n\t\t * Inputs:   int:iLevel - log error messages, or display them to the user\n\t\t *           string:sMesg - error message\n\t\t */\n\t\tfunction _fnLog( oSettings, iLevel, sMesg )\n\t\t{\n\t\t\tvar sAlert = oSettings.sTableId === \"\" ?\n\t\t\t \t\"DataTables warning: \" +sMesg :\n\t\t\t \t\"DataTables warning (table id = '\"+oSettings.sTableId+\"'): \" +sMesg;\n\t\t\t\n\t\t\tif ( iLevel === 0 )\n\t\t\t{\n\t\t\t\tif ( _oExt.sErrMode == 'alert' )\n\t\t\t\t{\n\t\t\t\t\talert( sAlert );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthrow sAlert;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if ( typeof console != 'undefined' && typeof console.log != 'undefined' )\n\t\t\t{\n\t\t\t\tconsole.log( sAlert );\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnClearTable\n\t\t * Purpose:  Nuke the table\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnClearTable( oSettings )\n\t\t{\n\t\t\toSettings.aoData.splice( 0, oSettings.aoData.length );\n\t\t\toSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );\n\t\t\toSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );\n\t\t\t_fnCalculateEnd( oSettings );\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnSaveState\n\t\t * Purpose:  Save the state of a table in a cookie such that the page can be reloaded\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t */\n\t\tfunction _fnSaveState ( oSettings )\n\t\t{\n\t\t\tif ( !oSettings.oFeatures.bStateSave || typeof oSettings.bDestroying != 'undefined' )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Store the interesting variables */\n\t\t\tvar i, iLen, sTmp;\n\t\t\tvar sValue = \"{\";\n\t\t\tsValue += '\"iCreate\":'+ new Date().getTime()+',';\n\t\t\tsValue += '\"iStart\":'+ oSettings._iDisplayStart+',';\n\t\t\tsValue += '\"iEnd\":'+ oSettings._iDisplayEnd+',';\n\t\t\tsValue += '\"iLength\":'+ oSettings._iDisplayLength+',';\n\t\t\tsValue += '\"sFilter\":\"'+ encodeURIComponent(oSettings.oPreviousSearch.sSearch)+'\",';\n\t\t\tsValue += '\"sFilterEsc\":'+ !oSettings.oPreviousSearch.bRegex+',';\n\t\t\t\n\t\t\tsValue += '\"aaSorting\":[ ';\n\t\t\tfor ( i=0 ; i<oSettings.aaSorting.length ; i++ )\n\t\t\t{\n\t\t\t\tsValue += '['+oSettings.aaSorting[i][0]+',\"'+oSettings.aaSorting[i][1]+'\"],';\n\t\t\t}\n\t\t\tsValue = sValue.substring(0, sValue.length-1);\n\t\t\tsValue += \"],\";\n\t\t\t\n\t\t\tsValue += '\"aaSearchCols\":[ ';\n\t\t\tfor ( i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )\n\t\t\t{\n\t\t\t\tsValue += '[\"'+encodeURIComponent(oSettings.aoPreSearchCols[i].sSearch)+\n\t\t\t\t\t'\",'+!oSettings.aoPreSearchCols[i].bRegex+'],';\n\t\t\t}\n\t\t\tsValue = sValue.substring(0, sValue.length-1);\n\t\t\tsValue += \"],\";\n\t\t\t\n\t\t\tsValue += '\"abVisCols\":[ ';\n\t\t\tfor ( i=0 ; i<oSettings.aoColumns.length ; i++ )\n\t\t\t{\n\t\t\t\tsValue += oSettings.aoColumns[i].bVisible+\",\";\n\t\t\t}\n\t\t\tsValue = sValue.substring(0, sValue.length-1);\n\t\t\tsValue += \"]\";\n\t\t\t\n\t\t\t/* Save state from any plug-ins */\n\t\t\tfor ( i=0, iLen=oSettings.aoStateSave.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tsTmp = oSettings.aoStateSave[i].fn( oSettings, sValue );\n\t\t\t\tif ( sTmp !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tsValue = sTmp;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tsValue += \"}\";\n\t\t\t\n\t\t\t_fnCreateCookie( oSettings.sCookiePrefix+oSettings.sInstance, sValue, \n\t\t\t\toSettings.iCookieDuration, oSettings.sCookiePrefix, oSettings.fnCookieCallback );\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnLoadState\n\t\t * Purpose:  Attempt to load a saved table state from a cookie\n\t\t * Returns:  -\n\t\t * Inputs:   object:oSettings - dataTables settings object\n\t\t *           object:oInit - DataTables init object so we can override settings\n\t\t */\n\t\tfunction _fnLoadState ( oSettings, oInit )\n\t\t{\n\t\t\tif ( !oSettings.oFeatures.bStateSave )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tvar oData, i, iLen;\n\t\t\tvar sData = _fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );\n\t\t\tif ( sData !== null && sData !== '' )\n\t\t\t{\n\t\t\t\t/* Try/catch the JSON eval - if it is bad then we ignore it - note that 1.7.0 and before\n\t\t\t\t * incorrectly used single quotes for some strings - hence the replace below\n\t\t\t\t */\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\toData = (typeof $.parseJSON == 'function') ? \n\t\t\t\t\t\t$.parseJSON( sData.replace(/'/g, '\"') ) : eval( '('+sData+')' );\n\t\t\t\t}\n\t\t\t\tcatch( e )\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Allow custom and plug-in manipulation functions to alter the data set which was\n\t\t\t\t * saved, and also reject any saved state by returning false\n\t\t\t\t */\n\t\t\t\tfor ( i=0, iLen=oSettings.aoStateLoad.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( !oSettings.aoStateLoad[i].fn( oSettings, oData ) )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Store the saved state so it might be accessed at any time (particualrly a plug-in */\n\t\t\t\toSettings.oLoadedState = $.extend( true, {}, oData );\n\t\t\t\t\n\t\t\t\t/* Restore key features */\n\t\t\t\toSettings._iDisplayStart = oData.iStart;\n\t\t\t\toSettings.iInitDisplayStart = oData.iStart;\n\t\t\t\toSettings._iDisplayEnd = oData.iEnd;\n\t\t\t\toSettings._iDisplayLength = oData.iLength;\n\t\t\t\toSettings.oPreviousSearch.sSearch = decodeURIComponent(oData.sFilter);\n\t\t\t\toSettings.aaSorting = oData.aaSorting.slice();\n\t\t\t\toSettings.saved_aaSorting = oData.aaSorting.slice();\n\t\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Search filtering - global reference added in 1.4.1\n\t\t\t\t * Note that we use a 'not' for the value of the regular expression indicator to maintain\n\t\t\t\t * compatibility with pre 1.7 versions, where this was basically inverted. Added in 1.7.0\n\t\t\t\t */\n\t\t\t\tif ( typeof oData.sFilterEsc != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\toSettings.oPreviousSearch.bRegex = !oData.sFilterEsc;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Column filtering - added in 1.5.0 beta 6 */\n\t\t\t\tif ( typeof oData.aaSearchCols != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\tfor ( i=0 ; i<oData.aaSearchCols.length ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aoPreSearchCols[i] = {\n\t\t\t\t\t\t\t\"sSearch\": decodeURIComponent(oData.aaSearchCols[i][0]),\n\t\t\t\t\t\t\t\"bRegex\": !oData.aaSearchCols[i][1]\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\t/* Column visibility state - added in 1.5.0 beta 10 */\n\t\t\t\tif ( typeof oData.abVisCols != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\t/* Pass back visibiliy settings to the init handler, but to do not here override\n\t\t\t\t\t * the init object that the user might have passed in\n\t\t\t\t\t */\n\t\t\t\t\toInit.saved_aoColumns = [];\n\t\t\t\t\tfor ( i=0 ; i<oData.abVisCols.length ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\toInit.saved_aoColumns[i] = {};\n\t\t\t\t\t\toInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnCreateCookie\n\t\t * Purpose:  Create a new cookie with a value to store the state of a table\n\t\t * Returns:  -\n\t\t * Inputs:   string:sName - name of the cookie to create\n\t\t *           string:sValue - the value the cookie should take\n\t\t *           int:iSecs - duration of the cookie\n\t\t *           string:sBaseName - sName is made up of the base + file name - this is the base\n\t\t *           function:fnCallback - User definable function to modify the cookie\n\t\t */\n\t\tfunction _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )\n\t\t{\n\t\t\tvar date = new Date();\n\t\t\tdate.setTime( date.getTime()+(iSecs*1000) );\n\t\t\t\n\t\t\t/* \n\t\t\t * Shocking but true - it would appear IE has major issues with having the path not having\n\t\t\t * a trailing slash on it. We need the cookie to be available based on the path, so we\n\t\t\t * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the\n\t\t\t * patch to use at least some of the path\n\t\t\t */\n\t\t\tvar aParts = window.location.pathname.split('/');\n\t\t\tvar sNameFile = sName + '_' + aParts.pop().replace(/[\\/:]/g,\"\").toLowerCase();\n\t\t\tvar sFullCookie, oData;\n\t\t\t\n\t\t\tif ( fnCallback !== null )\n\t\t\t{\n\t\t\t\toData = (typeof $.parseJSON == 'function') ? \n\t\t\t\t\t$.parseJSON( sValue ) : eval( '('+sValue+')' );\n\t\t\t\tsFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),\n\t\t\t\t\taParts.join('/')+\"/\" );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsFullCookie = sNameFile + \"=\" + encodeURIComponent(sValue) +\n\t\t\t\t\t\"; expires=\" + date.toGMTString() +\"; path=\" + aParts.join('/')+\"/\";\n\t\t\t}\n\t\t\t\n\t\t\t/* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies\n\t\t\t * belonging to DataTables. This is FAR from bullet proof\n\t\t\t */\n\t\t\tvar sOldName=\"\", iOldTime=9999999999999;\n\t\t\tvar iLength = _fnReadCookie( sNameFile )!==null ? document.cookie.length : \n\t\t\t\tsFullCookie.length + document.cookie.length;\n\t\t\t\n\t\t\tif ( iLength+10 > 4096 ) /* Magic 10 for padding */\n\t\t\t{\n\t\t\t\tvar aCookies =document.cookie.split(';');\n\t\t\t\tfor ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( aCookies[i].indexOf( sBaseName ) != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* It's a DataTables cookie, so eval it and check the time stamp */\n\t\t\t\t\t\tvar aSplitCookie = aCookies[i].split('=');\n\t\t\t\t\t\ttry { oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' ); }\n\t\t\t\t\t\tcatch( e ) { continue; }\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ( typeof oData.iCreate != 'undefined' && oData.iCreate < iOldTime )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsOldName = aSplitCookie[0];\n\t\t\t\t\t\t\tiOldTime = oData.iCreate;\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 ( sOldName !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tdocument.cookie = sOldName+\"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=\"+\n\t\t\t\t\t\taParts.join('/') + \"/\";\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tdocument.cookie = sFullCookie;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnReadCookie\n\t\t * Purpose:  Read an old cookie to get a cookie with an old table state\n\t\t * Returns:  string: - contents of the cookie - or null if no cookie with that name found\n\t\t * Inputs:   string:sName - name of the cookie to read\n\t\t */\n\t\tfunction _fnReadCookie ( sName )\n\t\t{\n\t\t\tvar\n\t\t\t\taParts = window.location.pathname.split('/'),\n\t\t\t\tsNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\\/:]/g,\"\").toLowerCase() + '=',\n\t\t\t \tsCookieContents = document.cookie.split(';');\n\t\t\t\n\t\t\tfor( var i=0 ; i<sCookieContents.length ; i++ )\n\t\t\t{\n\t\t\t\tvar c = sCookieContents[i];\n\t\t\t\t\n\t\t\t\twhile (c.charAt(0)==' ')\n\t\t\t\t{\n\t\t\t\t\tc = c.substring(1,c.length);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (c.indexOf(sNameEQ) === 0)\n\t\t\t\t{\n\t\t\t\t\treturn decodeURIComponent( c.substring(sNameEQ.length,c.length) );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnGetUniqueThs\n\t\t * Purpose:  Get an array of unique th elements, one for each column\n\t\t * Returns:  array node:aReturn - list of unique ths\n\t\t * Inputs:   node:nThead - The thead element for the table\n\t\t */\n\t\tfunction _fnGetUniqueThs ( nThead )\n\t\t{\n\t\t\tvar nTrs = nThead.getElementsByTagName('tr');\n\t\t\t\n\t\t\t/* Nice simple case */\n\t\t\tif ( nTrs.length == 1 )\n\t\t\t{\n\t\t\t\treturn nTrs[0].getElementsByTagName('th');\n\t\t\t}\n\t\t\t\n\t\t\t/* Otherwise we need to figure out the layout array to get the nodes */\n\t\t\tvar aLayout = [], aReturn = [];\n\t\t\tvar ROWSPAN = 2, COLSPAN = 3, TDELEM = 4;\n\t\t\tvar i, j, k, iLen, jLen, iColumnShifted;\n\t\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\t\twhile ( typeof a[i][j] != 'undefined' ) {\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t\treturn j;\n\t\t\t};\n\t\t\tvar fnAddRow = function ( i ) {\n\t\t\t\tif ( typeof aLayout[i] == 'undefined' ) {\n\t\t\t\t\taLayout[i] = [];\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Calculate a layout array */\n\t\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfnAddRow( i );\n\t\t\t\tvar iColumn = 0;\n\t\t\t\tvar nTds = [];\n\t\t\t\t\n\t\t\t\tfor ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( nTrs[i].childNodes[j].nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t\t     nTrs[i].childNodes[j].nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTds.push( nTrs[i].childNodes[j] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor ( j=0, jLen=nTds.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tvar iColspan = nTds[j].getAttribute('colspan') * 1;\n\t\t\t\t\tvar iRowspan = nTds[j].getAttribute('rowspan') * 1;\n\t\t\t\t\t\n\t\t\t\t\tif ( !iColspan || iColspan===0 || iColspan===1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tiColumnShifted = fnShiftCol( aLayout, i, iColumn );\n\t\t\t\t\t\taLayout[i][iColumnShifted] = (nTds[j].nodeName.toUpperCase()==\"TD\") ? TDELEM : nTds[j];\n\t\t\t\t\t\tif ( iRowspan || iRowspan===0 || iRowspan===1 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( k=1 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfnAddRow( i+k );\n\t\t\t\t\t\t\t\taLayout[i+k][iColumnShifted] = ROWSPAN;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColumn++;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tiColumnShifted = fnShiftCol( aLayout, i, iColumn );\n\t\t\t\t\t\tfor ( k=0 ; k<iColspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i][iColumnShifted+k] = COLSPAN;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColumn += iColspan;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Convert the layout array into a node array */\n\t\t\tfor ( i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfor ( j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aLayout[i][j] == 'object' )\n\t\t\t\t\t{\n\t\t\t\t\t\taReturn[j] = aLayout[i][j];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn aReturn;\n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnScrollBarWidth\n\t\t * Purpose:  Get the width of a scroll bar in this browser being used\n\t\t * Returns:  int: - width in pixels\n\t\t * Inputs:   -\n\t\t * Notes:    All credit for this function belongs to Alexandre Gomes. Thanks for sharing!\n\t\t *   http://www.alexandre-gomes.com/?p=115\n\t\t */\n\t\tfunction _fnScrollBarWidth ()\n\t\t{  \n\t\t\tvar inner = document.createElement('p');  \n\t\t\tvar style = inner.style;\n\t\t\tstyle.width = \"100%\";  \n\t\t\tstyle.height = \"200px\";  \n\t\t\t\n\t\t\tvar outer = document.createElement('div');  \n\t\t\tstyle = outer.style;\n\t\t\tstyle.position = \"absolute\";  \n\t\t\tstyle.top = \"0px\";  \n\t\t\tstyle.left = \"0px\";  \n\t\t\tstyle.visibility = \"hidden\";  \n\t\t\tstyle.width = \"200px\";  \n\t\t\tstyle.height = \"150px\";  \n\t\t\tstyle.overflow = \"hidden\";  \n\t\t\touter.appendChild(inner);  \n\t\t\t\n\t\t\tdocument.body.appendChild(outer);  \n\t\t\tvar w1 = inner.offsetWidth;  \n\t\t\touter.style.overflow = 'scroll';  \n\t\t\tvar w2 = inner.offsetWidth;  \n\t\t\tif ( w1 == w2 )\n\t\t\t{\n\t\t\t\tw2 = outer.clientWidth;  \n\t\t\t}\n\t\t\t\n\t\t\tdocument.body.removeChild(outer); \n\t\t\treturn (w1 - w2);  \n\t\t}\n\t\t\n\t\t/*\n\t\t * Function: _fnApplyToChildren\n\t\t * Purpose:  Apply a given function to the display child nodes of an element array (typically\n\t\t *   TD children of TR rows\n\t\t * Returns:  - (done by reference)\n\t\t * Inputs:   function:fn - Method to apply to the objects\n\t\t *           array nodes:an1 - List of elements to look through for display children\n\t\t *           array nodes:an2 - Another list (identical structure to the first) - optional\n\t\t */\n\t\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t\t{\n\t\t\tfor ( var i=0, iLen=an1.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfor ( var j=0, jLen=an1[i].childNodes.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( an1[i].childNodes[j].nodeType == 1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( typeof an2 != 'undefined' )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfn( an1[i].childNodes[j], an2[i].childNodes[j] );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfn( an1[i].childNodes[j] );\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\t\t\n\t\t/*\n\t\t * Function: _fnMap\n\t\t * Purpose:  See if a property is defined on one object, if so assign it to the other object\n\t\t * Returns:  - (done by reference)\n\t\t * Inputs:   object:oRet - target object\n\t\t *           object:oSrc - source object\n\t\t *           string:sName - property\n\t\t *           string:sMappedName - name to map too - optional, sName used if not given\n\t\t */\n\t\tfunction _fnMap( oRet, oSrc, sName, sMappedName )\n\t\t{\n\t\t\tif ( typeof sMappedName == 'undefined' )\n\t\t\t{\n\t\t\t\tsMappedName = sName;\n\t\t\t}\n\t\t\tif ( typeof oSrc[sName] != 'undefined' )\n\t\t\t{\n\t\t\t\toRet[sMappedName] = oSrc[sName];\n\t\t\t}\n\t\t}\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - API\n\t\t * \n\t\t * I'm not overly happy with this solution - I'd much rather that there was a way of getting\n\t\t * a list of all the private functions and do what we need to dynamically - but that doesn't\n\t\t * appear to be possible. Bonkers. A better solution would be to provide a 'bind' type object\n\t\t * To do - bind type method in DTs 2.x.\n\t\t */\n\t\tthis.oApi._fnExternApiFunc = _fnExternApiFunc;\n\t\tthis.oApi._fnInitalise = _fnInitalise;\n\t\tthis.oApi._fnLanguageProcess = _fnLanguageProcess;\n\t\tthis.oApi._fnAddColumn = _fnAddColumn;\n\t\tthis.oApi._fnColumnOptions = _fnColumnOptions;\n\t\tthis.oApi._fnAddData = _fnAddData;\n\t\tthis.oApi._fnGatherData = _fnGatherData;\n\t\tthis.oApi._fnDrawHead = _fnDrawHead;\n\t\tthis.oApi._fnDraw = _fnDraw;\n\t\tthis.oApi._fnReDraw = _fnReDraw;\n\t\tthis.oApi._fnAjaxUpdate = _fnAjaxUpdate;\n\t\tthis.oApi._fnAjaxUpdateDraw = _fnAjaxUpdateDraw;\n\t\tthis.oApi._fnAddOptionsHtml = _fnAddOptionsHtml;\n\t\tthis.oApi._fnFeatureHtmlTable = _fnFeatureHtmlTable;\n\t\tthis.oApi._fnScrollDraw = _fnScrollDraw;\n\t\tthis.oApi._fnAjustColumnSizing = _fnAjustColumnSizing;\n\t\tthis.oApi._fnFeatureHtmlFilter = _fnFeatureHtmlFilter;\n\t\tthis.oApi._fnFilterComplete = _fnFilterComplete;\n\t\tthis.oApi._fnFilterCustom = _fnFilterCustom;\n\t\tthis.oApi._fnFilterColumn = _fnFilterColumn;\n\t\tthis.oApi._fnFilter = _fnFilter;\n\t\tthis.oApi._fnBuildSearchArray = _fnBuildSearchArray;\n\t\tthis.oApi._fnBuildSearchRow = _fnBuildSearchRow;\n\t\tthis.oApi._fnFilterCreateSearch = _fnFilterCreateSearch;\n\t\tthis.oApi._fnDataToSearch = _fnDataToSearch;\n\t\tthis.oApi._fnSort = _fnSort;\n\t\tthis.oApi._fnSortAttachListener = _fnSortAttachListener;\n\t\tthis.oApi._fnSortingClasses = _fnSortingClasses;\n\t\tthis.oApi._fnFeatureHtmlPaginate = _fnFeatureHtmlPaginate;\n\t\tthis.oApi._fnPageChange = _fnPageChange;\n\t\tthis.oApi._fnFeatureHtmlInfo = _fnFeatureHtmlInfo;\n\t\tthis.oApi._fnUpdateInfo = _fnUpdateInfo;\n\t\tthis.oApi._fnFeatureHtmlLength = _fnFeatureHtmlLength;\n\t\tthis.oApi._fnFeatureHtmlProcessing = _fnFeatureHtmlProcessing;\n\t\tthis.oApi._fnProcessingDisplay = _fnProcessingDisplay;\n\t\tthis.oApi._fnVisibleToColumnIndex = _fnVisibleToColumnIndex;\n\t\tthis.oApi._fnColumnIndexToVisible = _fnColumnIndexToVisible;\n\t\tthis.oApi._fnNodeToDataIndex = _fnNodeToDataIndex;\n\t\tthis.oApi._fnVisbleColumns = _fnVisbleColumns;\n\t\tthis.oApi._fnCalculateEnd = _fnCalculateEnd;\n\t\tthis.oApi._fnConvertToWidth = _fnConvertToWidth;\n\t\tthis.oApi._fnCalculateColumnWidths = _fnCalculateColumnWidths;\n\t\tthis.oApi._fnScrollingWidthAdjust = _fnScrollingWidthAdjust;\n\t\tthis.oApi._fnGetWidestNode = _fnGetWidestNode;\n\t\tthis.oApi._fnGetMaxLenString = _fnGetMaxLenString;\n\t\tthis.oApi._fnStringToCss = _fnStringToCss;\n\t\tthis.oApi._fnArrayCmp = _fnArrayCmp;\n\t\tthis.oApi._fnDetectType = _fnDetectType;\n\t\tthis.oApi._fnSettingsFromNode = _fnSettingsFromNode;\n\t\tthis.oApi._fnGetDataMaster = _fnGetDataMaster;\n\t\tthis.oApi._fnGetTrNodes = _fnGetTrNodes;\n\t\tthis.oApi._fnGetTdNodes = _fnGetTdNodes;\n\t\tthis.oApi._fnEscapeRegex = _fnEscapeRegex;\n\t\tthis.oApi._fnDeleteIndex = _fnDeleteIndex;\n\t\tthis.oApi._fnReOrderIndex = _fnReOrderIndex;\n\t\tthis.oApi._fnColumnOrdering = _fnColumnOrdering;\n\t\tthis.oApi._fnLog = _fnLog;\n\t\tthis.oApi._fnClearTable = _fnClearTable;\n\t\tthis.oApi._fnSaveState = _fnSaveState;\n\t\tthis.oApi._fnLoadState = _fnLoadState;\n\t\tthis.oApi._fnCreateCookie = _fnCreateCookie;\n\t\tthis.oApi._fnReadCookie = _fnReadCookie;\n\t\tthis.oApi._fnGetUniqueThs = _fnGetUniqueThs;\n\t\tthis.oApi._fnScrollBarWidth = _fnScrollBarWidth;\n\t\tthis.oApi._fnApplyToChildren = _fnApplyToChildren;\n\t\tthis.oApi._fnMap = _fnMap;\n\t\t\n\t\t\n\t\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t\t * Section - Constructor\n\t\t */\n\t\t\n\t\t/* Want to be able to reference \"this\" inside the this.each function */\n\t\tvar _that = this;\n\t\treturn this.each(function()\n\t\t{\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\t\n\t\t\t/* Check to see if we are re-initalising a table */\n\t\t\tfor ( i=0, iLen=_aoSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif ( _aoSettings[i].nTable == this )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof oInit == 'undefined' || \n\t\t\t\t\t   ( typeof oInit.bRetrieve != 'undefined' && oInit.bRetrieve === true ) )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn _aoSettings[i].oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof oInit.bDestroy != 'undefined' && oInit.bDestroy === true )\n\t\t\t\t\t{\n\t\t\t\t\t\t_aoSettings[i].oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( _aoSettings[i], 0, \"Cannot reinitialise DataTable.\\n\\n\"+\n\t\t\t\t\t\t\t\"To retrieve the DataTables object for this table, please pass either no arguments \"+\n\t\t\t\t\t\t\t\"to the dataTable() function, or set bRetrieve to true. Alternatively, to destory \"+\n\t\t\t\t\t\t\t\"the old table and create a new one, set bDestroy to true (note that a lot of \"+\n\t\t\t\t\t\t\t\"changes to the configuration can be made through the API which is usually much \"+\n\t\t\t\t\t\t\t\"faster).\" );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destory the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( _aoSettings[i].sTableId !== \"\" && _aoSettings[i].sTableId == this.getAttribute('id') )\n\t\t\t\t{\n\t\t\t\t\t_aoSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Make a complete and independent copy of the settings object */\n\t\t\tvar oSettings = new classSettings();\n\t\t\t_aoSettings.push( oSettings );\n\t\t\t\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar bUsePassedData = false;\n\t\t\t\n\t\t\t/* Set the id */\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tif ( sId !== null )\n\t\t\t{\n\t\t\t\toSettings.sTableId = sId;\n\t\t\t\toSettings.sInstance = sId;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\toSettings.sInstance = _oExt._oExternConfig.iNextUnique ++;\n\t\t\t}\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( oSettings, 0, \"Attempted to initialise DataTables on a node which is not a \"+\n\t\t\t\t\t\"table: \"+this.nodeName );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Store 'this' in the settings object for later retrieval */\n\t\t\toSettings.oInstance = _that;\n\t\t\t\n\t\t\t/* Set the table node */\n\t\t\toSettings.nTable = this;\n\t\t\t\n\t\t\t/* Bind the API functions to the settings, so we can perform actions whenever oSettings is\n\t\t\t * available\n\t\t\t */\n\t\t\toSettings.oApi = _that.oApi;\n\t\t\t\n\t\t\t/* State the table's width for if a destroy is called at a later time */\n\t\t\toSettings.sDestroyWidth = $(this).width();\n\t\t\t\n\t\t\t/* Store the features that we have available */\n\t\t\tif ( typeof oInit != 'undefined' && oInit !== null )\n\t\t\t{\n\t\t\t\toSettings.oInit = oInit;\n\t\t\t\t_fnMap( oSettings.oFeatures, oInit, \"bPaginate\" );\n\t\t\t\t_fnMap( oSettings.oFeatures, oInit, \"bLengthChange\" );\n\t\t\t\t_fnMap( oSettings.oFeatures, oInit, \"bFilter\" );\n\t\t\t\t_fnMap( oSettings.oFeatures, oInit, \"bSort\" );\n\t\t\t\t_fnMap( oSettings.oFeatures, oInit, \"bInfo\" );\n\t\t\t\t_fnMap( oSettings.oFeatures, oInit, \"bProcessing\" );\n\t\t\t\t_fnMap( oSettings.oFeatures, oInit, \"bAutoWidth\" );\n\t\t\t\t_fnMap( oSettings.oFeatures, oInit, \"bSortClasses\" );\n\t\t\t\t_fnMap( oSettings.oFeatures, oInit, \"bServerSide\" );\n\t\t\t\t_fnMap( oSettings.oScroll, oInit, \"sScrollX\", \"sX\" );\n\t\t\t\t_fnMap( oSettings.oScroll, oInit, \"sScrollXInner\", \"sXInner\" );\n\t\t\t\t_fnMap( oSettings.oScroll, oInit, \"sScrollY\", \"sY\" );\n\t\t\t\t_fnMap( oSettings.oScroll, oInit, \"bScrollCollapse\", \"bCollapse\" );\n\t\t\t\t_fnMap( oSettings.oScroll, oInit, \"bScrollInfinite\", \"bInfinite\" );\n\t\t\t\t_fnMap( oSettings.oScroll, oInit, \"iScrollLoadGap\", \"iLoadGap\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"asStripClasses\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"fnRowCallback\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"fnHeaderCallback\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"fnFooterCallback\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"fnCookieCallback\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"fnInitComplete\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"fnServerData\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"fnFormatNumber\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"aaSorting\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"aaSortingFixed\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"aLengthMenu\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"sPaginationType\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"sAjaxSource\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"iCookieDuration\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"sCookiePrefix\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"sDom\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"oSearch\", \"oPreviousSearch\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"aoSearchCols\", \"aoPreSearchCols\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"iDisplayLength\", \"_iDisplayLength\" );\n\t\t\t\t_fnMap( oSettings, oInit, \"bJQueryUI\", \"bJUI\" );\n\t\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\t\n\t\t\t\t/* Callback functions which are array driven */\n\t\t\t\tif ( typeof oInit.fnDrawCallback == 'function' )\n\t\t\t\t{\n\t\t\t\t\toSettings.aoDrawCallback.push( {\n\t\t\t\t\t\t\"fn\": oInit.fnDrawCallback,\n\t\t\t\t\t\t\"sName\": \"user\"\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( typeof oInit.fnStateSaveCallback == 'function' )\n\t\t\t\t{\n\t\t\t\t\toSettings.aoStateSave.push( {\n\t\t\t\t\t\t\"fn\": oInit.fnStateSaveCallback,\n\t\t\t\t\t\t\"sName\": \"user\"\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( typeof oInit.fnStateLoadCallback == 'function' )\n\t\t\t\t{\n\t\t\t\t\toSettings.aoStateLoad.push( {\n\t\t\t\t\t\t\"fn\": oInit.fnStateLoadCallback,\n\t\t\t\t\t\t\"sName\": \"user\"\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&\n\t\t\t\t\t   oSettings.oFeatures.bSortClasses )\n\t\t\t\t{\n\t\t\t\t\t/* Enable sort classes for server-side processing. Safe to do it here, since server-side\n\t\t\t\t\t * processing must be enabled by the developer\n\t\t\t\t\t */\n\t\t\t\t\toSettings.aoDrawCallback.push( {\n\t\t\t\t\t\t\"fn\": _fnSortingClasses,\n\t\t\t\t\t\t\"sName\": \"server_side_sort_classes\"\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( typeof oInit.bJQueryUI != 'undefined' && oInit.bJQueryUI )\n\t\t\t\t{\n\t\t\t\t\t/* Use the JUI classes object for display. You could clone the oStdClasses object if \n\t\t\t\t\t * you want to have multiple tables with multiple independent classes \n\t\t\t\t\t */\n\t\t\t\t\toSettings.oClasses = _oExt.oJUIClasses;\n\t\t\t\t\t\n\t\t\t\t\tif ( typeof oInit.sDom == 'undefined' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Set the DOM to use a layout suitable for jQuery UI's theming */\n\t\t\t\t\t\toSettings.sDom = '<\"H\"lfr>t<\"F\"ip>';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Calculate the scroll bar width and cache it for use later on */\n\t\t\t\tif ( oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\" )\n\t\t\t\t{\n\t\t\t\t\toSettings.oScroll.iBarWidth = _fnScrollBarWidth();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( typeof oInit.iDisplayStart != 'undefined' && \n\t\t\t\t     typeof oSettings.iInitDisplayStart == 'undefined' )\n\t\t\t\t{\n\t\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Must be done after everything which can be overridden by a cookie! */\n\t\t\t\tif ( typeof oInit.bStateSave != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\toSettings.oFeatures.bStateSave = oInit.bStateSave;\n\t\t\t\t\t_fnLoadState( oSettings, oInit );\n\t\t\t\t\toSettings.aoDrawCallback.push( {\n\t\t\t\t\t\t\"fn\": _fnSaveState,\n\t\t\t\t\t\t\"sName\": \"state_save\"\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( typeof oInit.aaData != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\tbUsePassedData = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Backwards compatability */\n\t\t\t\t/* aoColumns / aoData - remove at some point... */\n\t\t\t\tif ( typeof oInit != 'undefined' && typeof oInit.aoData != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\toInit.aoColumns = oInit.aoData;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Language definitions */\n\t\t\t\tif ( typeof oInit.oLanguage != 'undefined' )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof oInit.oLanguage.sUrl != 'undefined' && oInit.oLanguage.sUrl !== \"\" )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Get the language definitions from a file */\n\t\t\t\t\t\toSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;\n\t\t\t\t\t\t$.getJSON( oSettings.oLanguage.sUrl, null, function( json ) { \n\t\t\t\t\t\t\t_fnLanguageProcess( oSettings, json, true ); } );\n\t\t\t\t\t\tbInitHandedOff = true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLanguageProcess( oSettings, oInit.oLanguage, false );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t/* Warning: The _fnLanguageProcess function is async to the remainder of this function due\n\t\t\t\t * to the XHR. We use _bInitialised in _fnLanguageProcess() to check this the processing \n\t\t\t\t * below is complete. The reason for spliting it like this is optimisation - we can fire\n\t\t\t\t * off the XHR (if needed) and then continue processing the data.\n\t\t\t\t */\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Create a dummy object for quick manipulation later on. */\n\t\t\t\toInit = {};\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t * Add the strip classes now that we know which classes to apply - unless overruled\n\t\t\t */\n\t\t\tif ( typeof oInit.asStripClasses == 'undefined' )\n\t\t\t{\n\t\t\t\toSettings.asStripClasses.push( oSettings.oClasses.sStripOdd );\n\t\t\t\toSettings.asStripClasses.push( oSettings.oClasses.sStripEven );\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar bStripeRemove = false;\n\t\t\tvar anRows = $('tbody>tr', this);\n\t\t\tfor ( i=0, iLen=oSettings.asStripClasses.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tif ( anRows.filter(\":lt(2)\").hasClass( oSettings.asStripClasses[i]) )\n\t\t\t\t{\n\t\t\t\t\tbStripeRemove = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\t\t\n\t\t\tif ( bStripeRemove )\n\t\t\t{\n\t\t\t\t/* Store the classes which we are about to remove so they can be readded on destory */\n\t\t\t\toSettings.asDestoryStrips = [ '', '' ];\n\t\t\t\tif ( $(anRows[0]).hasClass(oSettings.oClasses.sStripOdd) )\n\t\t\t\t{\n\t\t\t\t\toSettings.asDestoryStrips[0] += oSettings.oClasses.sStripOdd+\" \";\n\t\t\t\t}\n\t\t\t\tif ( $(anRows[0]).hasClass(oSettings.oClasses.sStripEven) )\n\t\t\t\t{\n\t\t\t\t\toSettings.asDestoryStrips[0] += oSettings.oClasses.sStripEven;\n\t\t\t\t}\n\t\t\t\tif ( $(anRows[1]).hasClass(oSettings.oClasses.sStripOdd) )\n\t\t\t\t{\n\t\t\t\t\toSettings.asDestoryStrips[1] += oSettings.oClasses.sStripOdd+\" \";\n\t\t\t\t}\n\t\t\t\tif ( $(anRows[1]).hasClass(oSettings.oClasses.sStripEven) )\n\t\t\t\t{\n\t\t\t\t\toSettings.asDestoryStrips[1] += oSettings.oClasses.sStripEven;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tanRows.removeClass( oSettings.asStripClasses.join(' ') );\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tvar anThs = nThead.length===0 ? [] : _fnGetUniqueThs( nThead[0] );\n\t\t\tvar aoColumnsInit;\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( typeof oInit.aoColumns == 'undefined' )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t/* Check if we have column visibilty state to restore */\n\t\t\t\tif ( typeof oInit.saved_aoColumns != 'undefined' && oInit.saved_aoColumns.length == iLen )\n\t\t\t\t{\n\t\t\t\t\tif ( aoColumnsInit[i] === null )\n\t\t\t\t\t{\n\t\t\t\t\t\taoColumnsInit[i] = {};\n\t\t\t\t\t}\n\t\t\t\t\taoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Add options from column definations */\n\t\t\tif ( typeof oInit.aoColumnDefs != 'undefined' )\n\t\t\t{\n\t\t\t\t/* Loop over the column defs array - loop in reverse so first instace has priority */\n\t\t\t\tfor ( i=oInit.aoColumnDefs.length-1 ; i>=0 ; i-- )\n\t\t\t\t{\n\t\t\t\t\t/* Each column def can target multiple columns, as it is an array */\n\t\t\t\t\tvar aTargets = oInit.aoColumnDefs[i].aTargets;\n\t\t\t\t\tif ( !$.isArray( aTargets ) )\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );\n\t\t\t\t\t}\n\t\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( typeof aTargets[j] == 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t/* 0+ integer, left to right column counting. We add columns which are unknown\n\t\t\t\t\t\t\t * automatically. Is this the right behaviour for this? We should at least\n\t\t\t\t\t\t\t * log it in future. We cannot do this for the negative or class targets, only here.\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\twhile( oSettings.aoColumns.length <= aTargets[j] )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, aTargets[j], oInit.aoColumnDefs[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( typeof aTargets[j] == 'number' && aTargets[j] < 0 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, oSettings.aoColumns.length+aTargets[j], \n\t\t\t\t\t\t\t\toInit.aoColumnDefs[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( typeof aTargets[j] == 'string' )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\t\tfor ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t\t     oSettings.aoColumns[k].nTh.className.indexOf( aTargets[j] ) != -1 )\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t_fnColumnOptions( oSettings, k, oInit.aoColumnDefs[i] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Add options from column array - after the defs array so this has priority */\n\t\t\tif ( typeof aoColumnsInit != 'undefined' )\n\t\t\t{\n\t\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t_fnColumnOptions( oSettings, i, aoColumnsInit[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Sorting\n\t\t\t * Check the aaSorting array\n\t\t\t */\n\t\t\tfor ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tif ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )\n\t\t\t\t{\n\t\t\t\t\toSettings.aaSorting[i][0] = 0;\n\t\t\t\t}\n\t\t\t\tvar oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];\n\t\t\t\t\n\t\t\t\t/* Add a default sorting index */\n\t\t\t\tif ( typeof oSettings.aaSorting[i][2] == 'undefined' )\n\t\t\t\t{\n\t\t\t\t\toSettings.aaSorting[i][2] = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* If aaSorting is not defined, then we use the first indicator in asSorting */\n\t\t\t\tif ( typeof oInit.aaSorting == \"undefined\" && \n\t\t\t\t\t\t typeof oSettings.saved_aaSorting == \"undefined\" )\n\t\t\t\t{\n\t\t\t\t\toSettings.aaSorting[i][1] = oColumn.asSorting[0];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* Set the current sorting index based on aoColumns.asSorting */\n\t\t\t\tfor ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )\n\t\t\t\t\t{\n\t\t\t\t\t\toSettings.aaSorting[i][2] = j;\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\t\t\n\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t */\n\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t/*\n\t\t\t * Final init\n\t\t\t * Sanity check that there is a thead and tbody. If not let's just create them\n\t\t\t */\n\t\t\tif ( this.getElementsByTagName('thead').length === 0 )\n\t\t\t{\n\t\t\t\tthis.appendChild( document.createElement( 'thead' ) );\n\t\t\t}\n\t\t\t\n\t\t\tif ( this.getElementsByTagName('tbody').length === 0 )\n\t\t\t{\n\t\t\t\tthis.appendChild( document.createElement( 'tbody' ) );\n\t\t\t}\n\t\t\t\n\t\t\toSettings.nTHead = this.getElementsByTagName('thead')[0];\n\t\t\toSettings.nTBody = this.getElementsByTagName('tbody')[0];\n\t\t\tif ( this.getElementsByTagName('tfoot').length > 0 )\n\t\t\t{\n\t\t\t\toSettings.nTFoot = this.getElementsByTagName('tfoot')[0];\n\t\t\t}\n\t\t\t\n\t\t\t/* Check if there is data passing into the constructor */\n\t\t\tif ( bUsePassedData )\n\t\t\t{\n\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Grab the data from the page */\n\t\t\t\t_fnGatherData( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* Copy the data index array */\n\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t * language processor)\n\t\t\t */\n\t\t\tif ( bInitHandedOff === false )\n\t\t\t{\n\t\t\t\t_fnInitalise( oSettings );\n\t\t\t}\n\t\t});\n\t};\n})(jQuery, window, document);\n"
  },
  {
    "path": "src/lib/jquery-ui-1.8.6/css/custom-theme/jquery-ui-1.8.6.custom.css",
    "content": "/*\n * jQuery UI CSS Framework 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Theming/API\n */\n\n/* Layout helpers\n----------------------------------*/\n.ui-helper-hidden { display: none; }\n.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }\n.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }\n.ui-helper-clearfix:after { content: \".\"; display: block; height: 0; clear: both; visibility: hidden; }\n.ui-helper-clearfix { display: inline-block; }\n/* required comment for clearfix to work in Opera \\*/\n* html .ui-helper-clearfix { height:1%; }\n.ui-helper-clearfix { display:block; }\n/* end clearfix */\n.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }\n\n\n/* Interaction Cues\n----------------------------------*/\n.ui-state-disabled { cursor: default !important; }\n\n\n/* Icons\n----------------------------------*/\n\n/* states and images */\n.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }\n\n\n/* Misc visuals\n----------------------------------*/\n\n/* Overlays */\n.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }\n\n\n/*\n * jQuery UI CSS Framework 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Theming/API\n *\n * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=\n */\n\n\n/* Component containers\n----------------------------------*/\n.ui-widget { font-family: ; font-size: 1.1em; }\n.ui-widget .ui-widget { font-size: 1em; }\n.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: ; font-size: 1em; }\n.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_75_ffffff_1x400.png) 50% 50% repeat-x; color: #222222; }\n.ui-widget-content a { color: #222222; }\n.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }\n.ui-widget-header a { color: #222222; }\n\n/* Interaction states\n----------------------------------*/\n.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }\n.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }\n.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }\n.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }\n.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }\n.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }\n.ui-widget :active { outline: none; }\n\n/* Interaction Cues\n----------------------------------*/\n.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }\n.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }\n.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_inset-soft_95_fef1ec_1x100.png) 50% bottom repeat-x; color: #cd0a0a; }\n.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }\n.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }\n.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }\n.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }\n.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }\n\n/* Icons\n----------------------------------*/\n\n/* states and images */\n.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }\n.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }\n.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }\n.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }\n.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }\n.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }\n.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }\n.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }\n\n/* positioning */\n.ui-icon-carat-1-n { background-position: 0 0; }\n.ui-icon-carat-1-ne { background-position: -16px 0; }\n.ui-icon-carat-1-e { background-position: -32px 0; }\n.ui-icon-carat-1-se { background-position: -48px 0; }\n.ui-icon-carat-1-s { background-position: -64px 0; }\n.ui-icon-carat-1-sw { background-position: -80px 0; }\n.ui-icon-carat-1-w { background-position: -96px 0; }\n.ui-icon-carat-1-nw { background-position: -112px 0; }\n.ui-icon-carat-2-n-s { background-position: -128px 0; }\n.ui-icon-carat-2-e-w { background-position: -144px 0; }\n.ui-icon-triangle-1-n { background-position: 0 -16px; }\n.ui-icon-triangle-1-ne { background-position: -16px -16px; }\n.ui-icon-triangle-1-e { background-position: -32px -16px; }\n.ui-icon-triangle-1-se { background-position: -48px -16px; }\n.ui-icon-triangle-1-s { background-position: -64px -16px; }\n.ui-icon-triangle-1-sw { background-position: -80px -16px; }\n.ui-icon-triangle-1-w { background-position: -96px -16px; }\n.ui-icon-triangle-1-nw { background-position: -112px -16px; }\n.ui-icon-triangle-2-n-s { background-position: -128px -16px; }\n.ui-icon-triangle-2-e-w { background-position: -144px -16px; }\n.ui-icon-arrow-1-n { background-position: 0 -32px; }\n.ui-icon-arrow-1-ne { background-position: -16px -32px; }\n.ui-icon-arrow-1-e { background-position: -32px -32px; }\n.ui-icon-arrow-1-se { background-position: -48px -32px; }\n.ui-icon-arrow-1-s { background-position: -64px -32px; }\n.ui-icon-arrow-1-sw { background-position: -80px -32px; }\n.ui-icon-arrow-1-w { background-position: -96px -32px; }\n.ui-icon-arrow-1-nw { background-position: -112px -32px; }\n.ui-icon-arrow-2-n-s { background-position: -128px -32px; }\n.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }\n.ui-icon-arrow-2-e-w { background-position: -160px -32px; }\n.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }\n.ui-icon-arrowstop-1-n { background-position: -192px -32px; }\n.ui-icon-arrowstop-1-e { background-position: -208px -32px; }\n.ui-icon-arrowstop-1-s { background-position: -224px -32px; }\n.ui-icon-arrowstop-1-w { background-position: -240px -32px; }\n.ui-icon-arrowthick-1-n { background-position: 0 -48px; }\n.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }\n.ui-icon-arrowthick-1-e { background-position: -32px -48px; }\n.ui-icon-arrowthick-1-se { background-position: -48px -48px; }\n.ui-icon-arrowthick-1-s { background-position: -64px -48px; }\n.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }\n.ui-icon-arrowthick-1-w { background-position: -96px -48px; }\n.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }\n.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }\n.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }\n.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }\n.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }\n.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }\n.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }\n.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }\n.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }\n.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }\n.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }\n.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }\n.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }\n.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }\n.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }\n.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }\n.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }\n.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }\n.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }\n.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }\n.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }\n.ui-icon-arrow-4 { background-position: 0 -80px; }\n.ui-icon-arrow-4-diag { background-position: -16px -80px; }\n.ui-icon-extlink { background-position: -32px -80px; }\n.ui-icon-newwin { background-position: -48px -80px; }\n.ui-icon-refresh { background-position: -64px -80px; }\n.ui-icon-shuffle { background-position: -80px -80px; }\n.ui-icon-transfer-e-w { background-position: -96px -80px; }\n.ui-icon-transferthick-e-w { background-position: -112px -80px; }\n.ui-icon-folder-collapsed { background-position: 0 -96px; }\n.ui-icon-folder-open { background-position: -16px -96px; }\n.ui-icon-document { background-position: -32px -96px; }\n.ui-icon-document-b { background-position: -48px -96px; }\n.ui-icon-note { background-position: -64px -96px; }\n.ui-icon-mail-closed { background-position: -80px -96px; }\n.ui-icon-mail-open { background-position: -96px -96px; }\n.ui-icon-suitcase { background-position: -112px -96px; }\n.ui-icon-comment { background-position: -128px -96px; }\n.ui-icon-person { background-position: -144px -96px; }\n.ui-icon-print { background-position: -160px -96px; }\n.ui-icon-trash { background-position: -176px -96px; }\n.ui-icon-locked { background-position: -192px -96px; }\n.ui-icon-unlocked { background-position: -208px -96px; }\n.ui-icon-bookmark { background-position: -224px -96px; }\n.ui-icon-tag { background-position: -240px -96px; }\n.ui-icon-home { background-position: 0 -112px; }\n.ui-icon-flag { background-position: -16px -112px; }\n.ui-icon-calendar { background-position: -32px -112px; }\n.ui-icon-cart { background-position: -48px -112px; }\n.ui-icon-pencil { background-position: -64px -112px; }\n.ui-icon-clock { background-position: -80px -112px; }\n.ui-icon-disk { background-position: -96px -112px; }\n.ui-icon-calculator { background-position: -112px -112px; }\n.ui-icon-zoomin { background-position: -128px -112px; }\n.ui-icon-zoomout { background-position: -144px -112px; }\n.ui-icon-search { background-position: -160px -112px; }\n.ui-icon-wrench { background-position: -176px -112px; }\n.ui-icon-gear { background-position: -192px -112px; }\n.ui-icon-heart { background-position: -208px -112px; }\n.ui-icon-star { background-position: -224px -112px; }\n.ui-icon-link { background-position: -240px -112px; }\n.ui-icon-cancel { background-position: 0 -128px; }\n.ui-icon-plus { background-position: -16px -128px; }\n.ui-icon-plusthick { background-position: -32px -128px; }\n.ui-icon-minus { background-position: -48px -128px; }\n.ui-icon-minusthick { background-position: -64px -128px; }\n.ui-icon-close { background-position: -80px -128px; }\n.ui-icon-closethick { background-position: -96px -128px; }\n.ui-icon-key { background-position: -112px -128px; }\n.ui-icon-lightbulb { background-position: -128px -128px; }\n.ui-icon-scissors { background-position: -144px -128px; }\n.ui-icon-clipboard { background-position: -160px -128px; }\n.ui-icon-copy { background-position: -176px -128px; }\n.ui-icon-contact { background-position: -192px -128px; }\n.ui-icon-image { background-position: -208px -128px; }\n.ui-icon-video { background-position: -224px -128px; }\n.ui-icon-script { background-position: -240px -128px; }\n.ui-icon-alert { background-position: 0 -144px; }\n.ui-icon-info { background-position: -16px -144px; }\n.ui-icon-notice { background-position: -32px -144px; }\n.ui-icon-help { background-position: -48px -144px; }\n.ui-icon-check { background-position: -64px -144px; }\n.ui-icon-bullet { background-position: -80px -144px; }\n.ui-icon-radio-off { background-position: -96px -144px; }\n.ui-icon-radio-on { background-position: -112px -144px; }\n.ui-icon-pin-w { background-position: -128px -144px; }\n.ui-icon-pin-s { background-position: -144px -144px; }\n.ui-icon-play { background-position: 0 -160px; }\n.ui-icon-pause { background-position: -16px -160px; }\n.ui-icon-seek-next { background-position: -32px -160px; }\n.ui-icon-seek-prev { background-position: -48px -160px; }\n.ui-icon-seek-end { background-position: -64px -160px; }\n.ui-icon-seek-start { background-position: -80px -160px; }\n/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */\n.ui-icon-seek-first { background-position: -80px -160px; }\n.ui-icon-stop { background-position: -96px -160px; }\n.ui-icon-eject { background-position: -112px -160px; }\n.ui-icon-volume-off { background-position: -128px -160px; }\n.ui-icon-volume-on { background-position: -144px -160px; }\n.ui-icon-power { background-position: 0 -176px; }\n.ui-icon-signal-diag { background-position: -16px -176px; }\n.ui-icon-signal { background-position: -32px -176px; }\n.ui-icon-battery-0 { background-position: -48px -176px; }\n.ui-icon-battery-1 { background-position: -64px -176px; }\n.ui-icon-battery-2 { background-position: -80px -176px; }\n.ui-icon-battery-3 { background-position: -96px -176px; }\n.ui-icon-circle-plus { background-position: 0 -192px; }\n.ui-icon-circle-minus { background-position: -16px -192px; }\n.ui-icon-circle-close { background-position: -32px -192px; }\n.ui-icon-circle-triangle-e { background-position: -48px -192px; }\n.ui-icon-circle-triangle-s { background-position: -64px -192px; }\n.ui-icon-circle-triangle-w { background-position: -80px -192px; }\n.ui-icon-circle-triangle-n { background-position: -96px -192px; }\n.ui-icon-circle-arrow-e { background-position: -112px -192px; }\n.ui-icon-circle-arrow-s { background-position: -128px -192px; }\n.ui-icon-circle-arrow-w { background-position: -144px -192px; }\n.ui-icon-circle-arrow-n { background-position: -160px -192px; }\n.ui-icon-circle-zoomin { background-position: -176px -192px; }\n.ui-icon-circle-zoomout { background-position: -192px -192px; }\n.ui-icon-circle-check { background-position: -208px -192px; }\n.ui-icon-circlesmall-plus { background-position: 0 -208px; }\n.ui-icon-circlesmall-minus { background-position: -16px -208px; }\n.ui-icon-circlesmall-close { background-position: -32px -208px; }\n.ui-icon-squaresmall-plus { background-position: -48px -208px; }\n.ui-icon-squaresmall-minus { background-position: -64px -208px; }\n.ui-icon-squaresmall-close { background-position: -80px -208px; }\n.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }\n.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }\n.ui-icon-grip-solid-vertical { background-position: -32px -224px; }\n.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }\n.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }\n.ui-icon-grip-diagonal-se { background-position: -80px -224px; }\n\n\n/* Misc visuals\n----------------------------------*/\n\n/* Corner radius */\n.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }\n.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }\n.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }\n.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }\n.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }\n.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }\n.ui-corner-right {  -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }\n.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }\n.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }\n\n/* Overlays */\n.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }\n.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*\n * jQuery UI Resizable 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Resizable#theming\n */\n.ui-resizable { position: relative;}\n.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}\n.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }\n.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }\n.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }\n.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }\n.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }\n.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }\n.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }\n.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }\n.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*\n * jQuery UI Selectable 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Selectable#theming\n */\n.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }\n/*\n * jQuery UI Accordion 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Accordion#theming\n */\n/* IE/Win - Fix animation bug - #4615 */\n.ui-accordion { width: 100%; }\n.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }\n.ui-accordion .ui-accordion-li-fix { display: inline; }\n.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }\n.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }\n.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }\n.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }\n.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }\n.ui-accordion .ui-accordion-content-active { display: block; }/*\n * jQuery UI Autocomplete 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Autocomplete#theming\n */\n.ui-autocomplete { position: absolute; cursor: default; }\t\n\n/* workarounds */\n* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */\n\n/*\n * jQuery UI Menu 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Menu#theming\n */\n.ui-menu {\n\tlist-style:none;\n\tpadding: 2px;\n\tmargin: 0;\n\tdisplay:block;\n\tfloat: left;\n}\n.ui-menu .ui-menu {\n\tmargin-top: -3px;\n}\n.ui-menu .ui-menu-item {\n\tmargin:0;\n\tpadding: 0;\n\tzoom: 1;\n\tfloat: left;\n\tclear: left;\n\twidth: 100%;\n}\n.ui-menu .ui-menu-item a {\n\ttext-decoration:none;\n\tdisplay:block;\n\tpadding:.2em .4em;\n\tline-height:1.5;\n\tzoom:1;\n}\n.ui-menu .ui-menu-item a.ui-state-hover,\n.ui-menu .ui-menu-item a.ui-state-active {\n\tfont-weight: normal;\n\tmargin: -1px;\n}\n/*\n * jQuery UI Button 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Button#theming\n */\n.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */\n.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */\nbutton.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */\n.ui-button-icons-only { width: 3.4em; } \nbutton.ui-button-icons-only { width: 3.7em; } \n\n/*button text element */\n.ui-button .ui-button-text { display: block; line-height: 1.4;  }\n.ui-button-text-only .ui-button-text { padding: .4em 1em; }\n.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }\n.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }\n.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }\n.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }\n/* no icon support for input elements, provide padding by default */\ninput.ui-button { padding: .4em 1em; }\n\n/*button icon element(s) */\n.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }\n.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }\n.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }\n.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }\n.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }\n\n/*button sets*/\n.ui-buttonset { margin-right: 7px; }\n.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }\n\n/* workarounds */\nbutton.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */\n/*\n * jQuery UI Dialog 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Dialog#theming\n */\n.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }\n.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative;  }\n.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } \n.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }\n.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }\n.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }\n.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }\n.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }\n.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }\n.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }\n.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }\n.ui-draggable .ui-dialog-titlebar { cursor: move; }\n/*\n * jQuery UI Slider 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Slider#theming\n */\n.ui-slider { position: relative; text-align: left; }\n.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }\n.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }\n\n.ui-slider-horizontal { height: .8em; }\n.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }\n.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }\n.ui-slider-horizontal .ui-slider-range-min { left: 0; }\n.ui-slider-horizontal .ui-slider-range-max { right: 0; }\n\n.ui-slider-vertical { width: .8em; height: 100px; }\n.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }\n.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }\n.ui-slider-vertical .ui-slider-range-min { bottom: 0; }\n.ui-slider-vertical .ui-slider-range-max { top: 0; }/*\n * jQuery UI Tabs 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Tabs#theming\n */\n.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as \"fixed\") */\n.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }\n.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }\n.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }\n.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }\n.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }\n.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */\n.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }\n.ui-tabs .ui-tabs-hide { display: none !important; }\n/*\n * jQuery UI Datepicker 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Datepicker#theming\n */\n.ui-datepicker { width: 17em; padding: .2em .2em 0; }\n.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }\n.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }\n.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }\n.ui-datepicker .ui-datepicker-prev { left:2px; }\n.ui-datepicker .ui-datepicker-next { right:2px; }\n.ui-datepicker .ui-datepicker-prev-hover { left:1px; }\n.ui-datepicker .ui-datepicker-next-hover { right:1px; }\n.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }\n.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }\n.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }\n.ui-datepicker select.ui-datepicker-month-year {width: 100%;}\n.ui-datepicker select.ui-datepicker-month, \n.ui-datepicker select.ui-datepicker-year { width: 49%;}\n.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }\n.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }\n.ui-datepicker td { border: 0; padding: 1px; }\n.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }\n.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }\n.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }\n.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }\n\n/* with multiple calendars */\n.ui-datepicker.ui-datepicker-multi { width:auto; }\n.ui-datepicker-multi .ui-datepicker-group { float:left; }\n.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }\n.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }\n.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }\n.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }\n.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }\n.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }\n.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }\n.ui-datepicker-row-break { clear:both; width:100%; }\n\n/* RTL support */\n.ui-datepicker-rtl { direction: rtl; }\n.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }\n.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }\n.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }\n.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }\n.ui-datepicker-rtl .ui-datepicker-group { float:right; }\n.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }\n.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }\n\n/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */\n.ui-datepicker-cover {\n    display: none; /*sorry for IE5*/\n    display/**/: block; /*sorry for IE5*/\n    position: absolute; /*must have*/\n    z-index: -1; /*must have*/\n    filter: mask(); /*must have*/\n    top: -4px; /*must have*/\n    left: -4px; /*must have*/\n    width: 200px; /*must have*/\n    height: 200px; /*must have*/\n}/*\n * jQuery UI Progressbar 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Progressbar#theming\n */\n.ui-progressbar { height:2em; text-align: left; }\n.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }"
  },
  {
    "path": "src/lib/jquery-ui-1.8.6/js/jquery-1.4.2.js",
    "content": "/*!\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(function( window, undefined ) {\n\n// Define a local copy of jQuery\nvar 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\njQuery.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\njQuery.fn.init.prototype = jQuery.fn;\n\njQuery.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\njQuery.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\nbrowserMatch = jQuery.uaMatch( userAgent );\nif ( browserMatch.browser ) {\n\tjQuery.browser[ browserMatch.browser ] = true;\n\tjQuery.browser.version = browserMatch.version;\n}\n\n// Deprecated, use jQuery.browser.webkit instead\nif ( jQuery.browser.webkit ) {\n\tjQuery.browser.safari = true;\n}\n\nif ( 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\nrootjQuery = jQuery(document);\n\n// Cleanup functions for the document ready method\nif ( 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\nfunction 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\nfunction 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\nfunction 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\nfunction 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\njQuery.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};\nvar expando = \"jQuery\" + now(), uuid = 0, windowData = {};\n\njQuery.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\njQuery.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});\njQuery.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\njQuery.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});\nvar 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\njQuery.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\njQuery.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});\nvar 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 */\njQuery.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\nvar 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\njQuery.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\nfunction returnFalse() {\n\treturn false;\n}\nfunction 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\njQuery.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\nvar 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.\ndelegate = function( event ) {\n\tevent.type = event.data;\n\tjQuery.event.handle.apply( this, arguments );\n};\n\n// Create mouseenter and mouseleave events\njQuery.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\nif ( !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.\nif ( !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\nfunction 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\nif ( 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\njQuery.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\njQuery.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\nvar liveMap = {\n\tfocus: \"focusin\",\n\tblur: \"focusout\",\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\n};\n\njQuery.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\nfunction 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\nfunction liveConvert( type, selector ) {\n\treturn \"live.\" + (type && type !== \"*\" ? type + \".\" : \"\") + selector.replace(/\\./g, \"`\").replace(/ /g, \"&\");\n}\n\njQuery.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/\nif ( 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\nvar 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\nvar 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\nSizzle.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\nSizzle.matches = function(expr, set){\n\treturn Sizzle(expr, null, null, set);\n};\n\nSizzle.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\nSizzle.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\nSizzle.error = function( msg ) {\n\tthrow \"Syntax error, unrecognized expression: \" + msg;\n};\n\nvar 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\nvar origPOS = Expr.match.POS;\n\nfor ( 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\nvar 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)\ntry {\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\nvar sortOrder;\n\nif ( 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\nfunction 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\nif ( 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\nfunction 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\nfunction 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\nvar 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\nvar 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\nvar 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\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.filters;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = getText;\njQuery.isXMLDoc = isXML;\njQuery.contains = contains;\n\nreturn;\n\nwindow.Sizzle = Sizzle;\n\n})();\nvar 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\nvar 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\njQuery.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).\nfunction isDisconnected( node ) {\n\treturn !node || !node.parentNode || node.parentNode.nodeType === 11;\n}\n\njQuery.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\njQuery.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});\nvar 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\nwrapMap.optgroup = wrapMap.option;\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// IE can't serialize <link> and <script> tags normally\nif ( !jQuery.support.htmlSerialize ) {\n\twrapMap._default = [ 1, \"div<div>\", \"</div>\" ];\n}\n\njQuery.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\nfunction 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\nfunction 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\njQuery.fragments = {};\n\njQuery.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\njQuery.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\nvar 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\njQuery.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\njQuery.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\nif ( 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}\nvar 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\njQuery.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\njQuery.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\njQuery.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});\nvar 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\njQuery.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\njQuery.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\njQuery.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\njQuery.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\njQuery.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\nif ( 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\nfunction 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}\nif ( \"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\njQuery.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\njQuery.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\njQuery.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\nfunction 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\njQuery.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// Expose jQuery to the global object\nwindow.jQuery = window.$ = jQuery;\n\n})(window);"
  },
  {
    "path": "src/lib/jquery-ui-1.8.6/js/jquery-ui-1.8.6.highlight.js",
    "content": "/*\n * jQuery UI Effects 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/\n */\n;jQuery.effects || (function($, undefined) {\n\n$.effects = {};\n\n\n\n/******************************************************************************/\n/****************************** COLOR ANIMATIONS ******************************/\n/******************************************************************************/\n\n// override the animation for color styles\n$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor',\n\t'borderRightColor', 'borderTopColor', 'borderColor', 'color', 'outlineColor'],\nfunction(i, attr) {\n\t$.fx.step[attr] = function(fx) {\n\t\tif (!fx.colorInit) {\n\t\t\tfx.start = getColor(fx.elem, attr);\n\t\t\tfx.end = getRGB(fx.end);\n\t\t\tfx.colorInit = true;\n\t\t}\n\n\t\tfx.elem.style[attr] = 'rgb(' +\n\t\t\tMath.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 255), 0) + ',' +\n\t\t\tMath.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 255), 0) + ',' +\n\t\t\tMath.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 255), 0) + ')';\n\t};\n});\n\n// Color Conversion functions from highlightFade\n// By Blair Mitchelmore\n// http://jquery.offput.ca/highlightFade/\n\n// Parse strings looking for color tuples [255,255,255]\nfunction getRGB(color) {\n\t\tvar result;\n\n\t\t// Check if we're already dealing with an array of colors\n\t\tif ( color && color.constructor == Array && color.length == 3 )\n\t\t\t\treturn color;\n\n\t\t// Look for rgb(num,num,num)\n\t\tif (result = /rgb\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)/.exec(color))\n\t\t\t\treturn [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)];\n\n\t\t// Look for rgb(num%,num%,num%)\n\t\tif (result = /rgb\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)/.exec(color))\n\t\t\t\treturn [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];\n\n\t\t// Look for #a0b1c2\n\t\tif (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))\n\t\t\t\treturn [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];\n\n\t\t// Look for #fff\n\t\tif (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))\n\t\t\t\treturn [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];\n\n\t\t// Look for rgba(0, 0, 0, 0) == transparent in Safari 3\n\t\tif (result = /rgba\\(0, 0, 0, 0\\)/.exec(color))\n\t\t\t\treturn colors['transparent'];\n\n\t\t// Otherwise, we're most likely dealing with a named color\n\t\treturn colors[$.trim(color).toLowerCase()];\n}\n\nfunction getColor(elem, attr) {\n\t\tvar color;\n\n\t\tdo {\n\t\t\t\tcolor = $.curCSS(elem, attr);\n\n\t\t\t\t// Keep going until we find an element that has color, or we hit the body\n\t\t\t\tif ( color != '' && color != 'transparent' || $.nodeName(elem, \"body\") )\n\t\t\t\t\t\tbreak;\n\n\t\t\t\tattr = \"backgroundColor\";\n\t\t} while ( elem = elem.parentNode );\n\n\t\treturn getRGB(color);\n};\n\n// Some named colors to work with\n// From Interface by Stefan Petre\n// http://interface.eyecon.ro/\n\nvar colors = {\n\taqua:[0,255,255],\n\tazure:[240,255,255],\n\tbeige:[245,245,220],\n\tblack:[0,0,0],\n\tblue:[0,0,255],\n\tbrown:[165,42,42],\n\tcyan:[0,255,255],\n\tdarkblue:[0,0,139],\n\tdarkcyan:[0,139,139],\n\tdarkgrey:[169,169,169],\n\tdarkgreen:[0,100,0],\n\tdarkkhaki:[189,183,107],\n\tdarkmagenta:[139,0,139],\n\tdarkolivegreen:[85,107,47],\n\tdarkorange:[255,140,0],\n\tdarkorchid:[153,50,204],\n\tdarkred:[139,0,0],\n\tdarksalmon:[233,150,122],\n\tdarkviolet:[148,0,211],\n\tfuchsia:[255,0,255],\n\tgold:[255,215,0],\n\tgreen:[0,128,0],\n\tindigo:[75,0,130],\n\tkhaki:[240,230,140],\n\tlightblue:[173,216,230],\n\tlightcyan:[224,255,255],\n\tlightgreen:[144,238,144],\n\tlightgrey:[211,211,211],\n\tlightpink:[255,182,193],\n\tlightyellow:[255,255,224],\n\tlime:[0,255,0],\n\tmagenta:[255,0,255],\n\tmaroon:[128,0,0],\n\tnavy:[0,0,128],\n\tolive:[128,128,0],\n\torange:[255,165,0],\n\tpink:[255,192,203],\n\tpurple:[128,0,128],\n\tviolet:[128,0,128],\n\tred:[255,0,0],\n\tsilver:[192,192,192],\n\twhite:[255,255,255],\n\tyellow:[255,255,0],\n\ttransparent: [255,255,255]\n};\n\n\n\n/******************************************************************************/\n/****************************** CLASS ANIMATIONS ******************************/\n/******************************************************************************/\n\nvar classAnimationActions = ['add', 'remove', 'toggle'],\n\tshorthandStyles = {\n\t\tborder: 1,\n\t\tborderBottom: 1,\n\t\tborderColor: 1,\n\t\tborderLeft: 1,\n\t\tborderRight: 1,\n\t\tborderTop: 1,\n\t\tborderWidth: 1,\n\t\tmargin: 1,\n\t\tpadding: 1\n\t};\n\nfunction getElementStyles() {\n\tvar style = document.defaultView\n\t\t\t? document.defaultView.getComputedStyle(this, null)\n\t\t\t: this.currentStyle,\n\t\tnewStyle = {},\n\t\tkey,\n\t\tcamelCase;\n\n\t// webkit enumerates style porperties\n\tif (style && style.length && style[0] && style[style[0]]) {\n\t\tvar len = style.length;\n\t\twhile (len--) {\n\t\t\tkey = style[len];\n\t\t\tif (typeof style[key] == 'string') {\n\t\t\t\tcamelCase = key.replace(/\\-(\\w)/g, function(all, letter){\n\t\t\t\t\treturn letter.toUpperCase();\n\t\t\t\t});\n\t\t\t\tnewStyle[camelCase] = style[key];\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (key in style) {\n\t\t\tif (typeof style[key] === 'string') {\n\t\t\t\tnewStyle[key] = style[key];\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn newStyle;\n}\n\nfunction filterStyles(styles) {\n\tvar name, value;\n\tfor (name in styles) {\n\t\tvalue = styles[name];\n\t\tif (\n\t\t\t// ignore null and undefined values\n\t\t\tvalue == null ||\n\t\t\t// ignore functions (when does this occur?)\n\t\t\t$.isFunction(value) ||\n\t\t\t// shorthand styles that need to be expanded\n\t\t\tname in shorthandStyles ||\n\t\t\t// ignore scrollbars (break in IE)\n\t\t\t(/scrollbar/).test(name) ||\n\n\t\t\t// only colors or values that can be converted to numbers\n\t\t\t(!(/color/i).test(name) && isNaN(parseFloat(value)))\n\t\t) {\n\t\t\tdelete styles[name];\n\t\t}\n\t}\n\t\n\treturn styles;\n}\n\nfunction styleDifference(oldStyle, newStyle) {\n\tvar diff = { _: 0 }, // http://dev.jquery.com/ticket/5459\n\t\tname;\n\n\tfor (name in newStyle) {\n\t\tif (oldStyle[name] != newStyle[name]) {\n\t\t\tdiff[name] = newStyle[name];\n\t\t}\n\t}\n\n\treturn diff;\n}\n\n$.effects.animateClass = function(value, duration, easing, callback) {\n\tif ($.isFunction(easing)) {\n\t\tcallback = easing;\n\t\teasing = null;\n\t}\n\n\treturn this.each(function() {\n\n\t\tvar that = $(this),\n\t\t\toriginalStyleAttr = that.attr('style') || ' ',\n\t\t\toriginalStyle = filterStyles(getElementStyles.call(this)),\n\t\t\tnewStyle,\n\t\t\tclassName = that.attr('className');\n\n\t\t$.each(classAnimationActions, function(i, action) {\n\t\t\tif (value[action]) {\n\t\t\t\tthat[action + 'Class'](value[action]);\n\t\t\t}\n\t\t});\n\t\tnewStyle = filterStyles(getElementStyles.call(this));\n\t\tthat.attr('className', className);\n\n\t\tthat.animate(styleDifference(originalStyle, newStyle), duration, easing, function() {\n\t\t\t$.each(classAnimationActions, function(i, action) {\n\t\t\t\tif (value[action]) { that[action + 'Class'](value[action]); }\n\t\t\t});\n\t\t\t// work around bug in IE by clearing the cssText before setting it\n\t\t\tif (typeof that.attr('style') == 'object') {\n\t\t\t\tthat.attr('style').cssText = '';\n\t\t\t\tthat.attr('style').cssText = originalStyleAttr;\n\t\t\t} else {\n\t\t\t\tthat.attr('style', originalStyleAttr);\n\t\t\t}\n\t\t\tif (callback) { callback.apply(this, arguments); }\n\t\t});\n\t});\n};\n\n$.fn.extend({\n\t_addClass: $.fn.addClass,\n\taddClass: function(classNames, speed, easing, callback) {\n\t\treturn speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames);\n\t},\n\n\t_removeClass: $.fn.removeClass,\n\tremoveClass: function(classNames,speed,easing,callback) {\n\t\treturn speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames);\n\t},\n\n\t_toggleClass: $.fn.toggleClass,\n\ttoggleClass: function(classNames, force, speed, easing, callback) {\n\t\tif ( typeof force == \"boolean\" || force === undefined ) {\n\t\t\tif ( !speed ) {\n\t\t\t\t// without speed parameter;\n\t\t\t\treturn this._toggleClass(classNames, force);\n\t\t\t} else {\n\t\t\t\treturn $.effects.animateClass.apply(this, [(force?{add:classNames}:{remove:classNames}),speed,easing,callback]);\n\t\t\t}\n\t\t} else {\n\t\t\t// without switch parameter;\n\t\t\treturn $.effects.animateClass.apply(this, [{ toggle: classNames },force,speed,easing]);\n\t\t}\n\t},\n\n\tswitchClass: function(remove,add,speed,easing,callback) {\n\t\treturn $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]);\n\t}\n});\n\n\n\n/******************************************************************************/\n/*********************************** EFFECTS **********************************/\n/******************************************************************************/\n\n$.extend($.effects, {\n\tversion: \"1.8.6\",\n\n\t// Saves a set of properties in a data storage\n\tsave: function(element, set) {\n\t\tfor(var i=0; i < set.length; i++) {\n\t\t\tif(set[i] !== null) element.data(\"ec.storage.\"+set[i], element[0].style[set[i]]);\n\t\t}\n\t},\n\n\t// Restores a set of previously saved properties from a data storage\n\trestore: function(element, set) {\n\t\tfor(var i=0; i < set.length; i++) {\n\t\t\tif(set[i] !== null) element.css(set[i], element.data(\"ec.storage.\"+set[i]));\n\t\t}\n\t},\n\n\tsetMode: function(el, mode) {\n\t\tif (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle\n\t\treturn mode;\n\t},\n\n\tgetBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value\n\t\t// this should be a little more flexible in the future to handle a string & hash\n\t\tvar y, x;\n\t\tswitch (origin[0]) {\n\t\t\tcase 'top': y = 0; break;\n\t\t\tcase 'middle': y = 0.5; break;\n\t\t\tcase 'bottom': y = 1; break;\n\t\t\tdefault: y = origin[0] / original.height;\n\t\t};\n\t\tswitch (origin[1]) {\n\t\t\tcase 'left': x = 0; break;\n\t\t\tcase 'center': x = 0.5; break;\n\t\t\tcase 'right': x = 1; break;\n\t\t\tdefault: x = origin[1] / original.width;\n\t\t};\n\t\treturn {x: x, y: y};\n\t},\n\n\t// Wraps the element around a wrapper that copies position properties\n\tcreateWrapper: function(element) {\n\n\t\t// if the element is already wrapped, return it\n\t\tif (element.parent().is('.ui-effects-wrapper')) {\n\t\t\treturn element.parent();\n\t\t}\n\n\t\t// wrap the element\n\t\tvar props = {\n\t\t\t\twidth: element.outerWidth(true),\n\t\t\t\theight: element.outerHeight(true),\n\t\t\t\t'float': element.css('float')\n\t\t\t},\n\t\t\twrapper = $('<div></div>')\n\t\t\t\t.addClass('ui-effects-wrapper')\n\t\t\t\t.css({\n\t\t\t\t\tfontSize: '100%',\n\t\t\t\t\tbackground: 'transparent',\n\t\t\t\t\tborder: 'none',\n\t\t\t\t\tmargin: 0,\n\t\t\t\t\tpadding: 0\n\t\t\t\t});\n\n\t\telement.wrap(wrapper);\n\t\twrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element\n\n\t\t// transfer positioning properties to the wrapper\n\t\tif (element.css('position') == 'static') {\n\t\t\twrapper.css({ position: 'relative' });\n\t\t\telement.css({ position: 'relative' });\n\t\t} else {\n\t\t\t$.extend(props, {\n\t\t\t\tposition: element.css('position'),\n\t\t\t\tzIndex: element.css('z-index')\n\t\t\t});\n\t\t\t$.each(['top', 'left', 'bottom', 'right'], function(i, pos) {\n\t\t\t\tprops[pos] = element.css(pos);\n\t\t\t\tif (isNaN(parseInt(props[pos], 10))) {\n\t\t\t\t\tprops[pos] = 'auto';\n\t\t\t\t}\n\t\t\t});\n\t\t\telement.css({position: 'relative', top: 0, left: 0 });\n\t\t}\n\n\t\treturn wrapper.css(props).show();\n\t},\n\n\tremoveWrapper: function(element) {\n\t\tif (element.parent().is('.ui-effects-wrapper'))\n\t\t\treturn element.parent().replaceWith(element);\n\t\treturn element;\n\t},\n\n\tsetTransition: function(element, list, factor, value) {\n\t\tvalue = value || {};\n\t\t$.each(list, function(i, x){\n\t\t\tunit = element.cssUnit(x);\n\t\t\tif (unit[0] > 0) value[x] = unit[0] * factor + unit[1];\n\t\t});\n\t\treturn value;\n\t}\n});\n\n\nfunction _normalizeArguments(effect, options, speed, callback) {\n\t// shift params for method overloading\n\tif (typeof effect == 'object') {\n\t\tcallback = options;\n\t\tspeed = null;\n\t\toptions = effect;\n\t\teffect = options.effect;\n\t}\n\tif ($.isFunction(options)) {\n\t\tcallback = options;\n\t\tspeed = null;\n\t\toptions = {};\n\t}\n        if (typeof options == 'number' || $.fx.speeds[options]) {\n\t\tcallback = speed;\n\t\tspeed = options;\n\t\toptions = {};\n\t}\n\tif ($.isFunction(speed)) {\n\t\tcallback = speed;\n\t\tspeed = null;\n\t}\n\n\toptions = options || {};\n\n\tspeed = speed || options.duration;\n\tspeed = $.fx.off ? 0 : typeof speed == 'number'\n\t\t? speed : $.fx.speeds[speed] || $.fx.speeds._default;\n\n\tcallback = callback || options.complete;\n\n\treturn [effect, options, speed, callback];\n}\n\nfunction standardSpeed( speed ) {\n\t// valid standard speeds\n\tif ( !speed || typeof speed === \"number\" || $.fx.speeds[ speed ] ) {\n\t\treturn true;\n\t}\n\t\n\t// invalid strings - treat as \"normal\" speed\n\tif ( typeof speed === \"string\" && !$.effects[ speed ] ) {\n\t\treturn true;\n\t}\n\t\n\treturn false;\n}\n\n$.fn.extend({\n\teffect: function(effect, options, speed, callback) {\n\t\tvar args = _normalizeArguments.apply(this, arguments),\n\t\t\t// TODO: make effects take actual parameters instead of a hash\n\t\t\targs2 = {\n\t\t\t\toptions: args[1],\n\t\t\t\tduration: args[2],\n\t\t\t\tcallback: args[3]\n\t\t\t},\n\t\t\tmode = args2.options.mode,\n\t\t\teffectMethod = $.effects[effect];\n\t\t\n\t\tif ( $.fx.off || !effectMethod ) {\n\t\t\t// delegate to the original method (e.g., .show()) if possible\n\t\t\tif ( mode ) {\n\t\t\t\treturn this[ mode ]( args2.duration, args2.callback );\n\t\t\t} else {\n\t\t\t\treturn this.each(function() {\n\t\t\t\t\tif ( args2.callback ) {\n\t\t\t\t\t\targs2.callback.call( this );\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn effectMethod.call(this, args2);\n\t},\n\n\t_show: $.fn.show,\n\tshow: function(speed) {\n\t\tif ( standardSpeed( speed ) ) {\n\t\t\treturn this._show.apply(this, arguments);\n\t\t} else {\n\t\t\tvar args = _normalizeArguments.apply(this, arguments);\n\t\t\targs[1].mode = 'show';\n\t\t\treturn this.effect.apply(this, args);\n\t\t}\n\t},\n\n\t_hide: $.fn.hide,\n\thide: function(speed) {\n\t\tif ( standardSpeed( speed ) ) {\n\t\t\treturn this._hide.apply(this, arguments);\n\t\t} else {\n\t\t\tvar args = _normalizeArguments.apply(this, arguments);\n\t\t\targs[1].mode = 'hide';\n\t\t\treturn this.effect.apply(this, args);\n\t\t}\n\t},\n\n\t// jQuery core overloads toggle and creates _toggle\n\t__toggle: $.fn.toggle,\n\ttoggle: function(speed) {\n\t\tif ( standardSpeed( speed ) || typeof speed === \"boolean\" || $.isFunction( speed ) ) {\n\t\t\treturn this.__toggle.apply(this, arguments);\n\t\t} else {\n\t\t\tvar args = _normalizeArguments.apply(this, arguments);\n\t\t\targs[1].mode = 'toggle';\n\t\t\treturn this.effect.apply(this, args);\n\t\t}\n\t},\n\n\t// helper functions\n\tcssUnit: function(key) {\n\t\tvar style = this.css(key), val = [];\n\t\t$.each( ['em','px','%','pt'], function(i, unit){\n\t\t\tif(style.indexOf(unit) > 0)\n\t\t\t\tval = [parseFloat(style), unit];\n\t\t});\n\t\treturn val;\n\t}\n});\n\n\n\n/******************************************************************************/\n/*********************************** EASING ***********************************/\n/******************************************************************************/\n\n/*\n * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/\n *\n * Uses the built in easing capabilities added In jQuery 1.1\n * to offer multiple easing options\n *\n * TERMS OF USE - jQuery Easing\n *\n * Open source under the BSD License.\n *\n * Copyright 2008 George McGinley Smith\n * All rights reserved.\n *\n * Redistribution and use 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 copyright notice, this list of\n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list\n * of conditions and the following disclaimer in the documentation and/or other materials\n * provided with the distribution.\n *\n * Neither the name of the author nor the names of contributors may be used to endorse\n * or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n*/\n\n// t: current time, b: begInnIng value, c: change In value, d: duration\n$.easing.jswing = $.easing.swing;\n\n$.extend($.easing,\n{\n\tdef: 'easeOutQuad',\n\tswing: function (x, t, b, c, d) {\n\t\t//alert($.easing.default);\n\t\treturn $.easing[$.easing.def](x, t, b, c, d);\n\t},\n\teaseInQuad: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t + b;\n\t},\n\teaseOutQuad: function (x, t, b, c, d) {\n\t\treturn -c *(t/=d)*(t-2) + b;\n\t},\n\teaseInOutQuad: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t + b;\n\t\treturn -c/2 * ((--t)*(t-2) - 1) + b;\n\t},\n\teaseInCubic: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t*t + b;\n\t},\n\teaseOutCubic: function (x, t, b, c, d) {\n\t\treturn c*((t=t/d-1)*t*t + 1) + b;\n\t},\n\teaseInOutCubic: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t*t + b;\n\t\treturn c/2*((t-=2)*t*t + 2) + b;\n\t},\n\teaseInQuart: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t*t*t + b;\n\t},\n\teaseOutQuart: function (x, t, b, c, d) {\n\t\treturn -c * ((t=t/d-1)*t*t*t - 1) + b;\n\t},\n\teaseInOutQuart: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t*t*t + b;\n\t\treturn -c/2 * ((t-=2)*t*t*t - 2) + b;\n\t},\n\teaseInQuint: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t*t*t*t + b;\n\t},\n\teaseOutQuint: function (x, t, b, c, d) {\n\t\treturn c*((t=t/d-1)*t*t*t*t + 1) + b;\n\t},\n\teaseInOutQuint: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;\n\t\treturn c/2*((t-=2)*t*t*t*t + 2) + b;\n\t},\n\teaseInSine: function (x, t, b, c, d) {\n\t\treturn -c * Math.cos(t/d * (Math.PI/2)) + c + b;\n\t},\n\teaseOutSine: function (x, t, b, c, d) {\n\t\treturn c * Math.sin(t/d * (Math.PI/2)) + b;\n\t},\n\teaseInOutSine: function (x, t, b, c, d) {\n\t\treturn -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;\n\t},\n\teaseInExpo: function (x, t, b, c, d) {\n\t\treturn (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;\n\t},\n\teaseOutExpo: function (x, t, b, c, d) {\n\t\treturn (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;\n\t},\n\teaseInOutExpo: function (x, t, b, c, d) {\n\t\tif (t==0) return b;\n\t\tif (t==d) return b+c;\n\t\tif ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;\n\t\treturn c/2 * (-Math.pow(2, -10 * --t) + 2) + b;\n\t},\n\teaseInCirc: function (x, t, b, c, d) {\n\t\treturn -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;\n\t},\n\teaseOutCirc: function (x, t, b, c, d) {\n\t\treturn c * Math.sqrt(1 - (t=t/d-1)*t) + b;\n\t},\n\teaseInOutCirc: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;\n\t\treturn c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;\n\t},\n\teaseInElastic: function (x, t, b, c, d) {\n\t\tvar s=1.70158;var p=0;var a=c;\n\t\tif (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;\n\t\tif (a < Math.abs(c)) { a=c; var s=p/4; }\n\t\telse var s = p/(2*Math.PI) * Math.asin (c/a);\n\t\treturn -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;\n\t},\n\teaseOutElastic: function (x, t, b, c, d) {\n\t\tvar s=1.70158;var p=0;var a=c;\n\t\tif (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;\n\t\tif (a < Math.abs(c)) { a=c; var s=p/4; }\n\t\telse var s = p/(2*Math.PI) * Math.asin (c/a);\n\t\treturn a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;\n\t},\n\teaseInOutElastic: function (x, t, b, c, d) {\n\t\tvar s=1.70158;var p=0;var a=c;\n\t\tif (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);\n\t\tif (a < Math.abs(c)) { a=c; var s=p/4; }\n\t\telse var s = p/(2*Math.PI) * Math.asin (c/a);\n\t\tif (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;\n\t\treturn a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;\n\t},\n\teaseInBack: function (x, t, b, c, d, s) {\n\t\tif (s == undefined) s = 1.70158;\n\t\treturn c*(t/=d)*t*((s+1)*t - s) + b;\n\t},\n\teaseOutBack: function (x, t, b, c, d, s) {\n\t\tif (s == undefined) s = 1.70158;\n\t\treturn c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;\n\t},\n\teaseInOutBack: function (x, t, b, c, d, s) {\n\t\tif (s == undefined) s = 1.70158;\n\t\tif ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;\n\t\treturn c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;\n\t},\n\teaseInBounce: function (x, t, b, c, d) {\n\t\treturn c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b;\n\t},\n\teaseOutBounce: function (x, t, b, c, d) {\n\t\tif ((t/=d) < (1/2.75)) {\n\t\t\treturn c*(7.5625*t*t) + b;\n\t\t} else if (t < (2/2.75)) {\n\t\t\treturn c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;\n\t\t} else if (t < (2.5/2.75)) {\n\t\t\treturn c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;\n\t\t} else {\n\t\t\treturn c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;\n\t\t}\n\t},\n\teaseInOutBounce: function (x, t, b, c, d) {\n\t\tif (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;\n\t\treturn $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;\n\t}\n});\n\n/*\n *\n * TERMS OF USE - EASING EQUATIONS\n *\n * Open source under the BSD License.\n *\n * Copyright 2001 Robert Penner\n * All rights reserved.\n *\n * Redistribution and use 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 copyright notice, this list of\n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list\n * of conditions and the following disclaimer in the documentation and/or other materials\n * provided with the distribution.\n *\n * Neither the name of the author nor the names of contributors may be used to endorse\n * or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n})(jQuery);\n/*\n * jQuery UI Effects Highlight 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Highlight\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.highlight = function(o) {\n\treturn this.queue(function() {\n\t\tvar elem = $(this),\n\t\t\tprops = ['backgroundImage', 'backgroundColor', 'opacity'],\n\t\t\tmode = $.effects.setMode(elem, o.options.mode || 'show'),\n\t\t\tanimation = {\n\t\t\t\tbackgroundColor: elem.css('backgroundColor')\n\t\t\t};\n\n\t\tif (mode == 'hide') {\n\t\t\tanimation.opacity = 0;\n\t\t}\n\n\t\t$.effects.save(elem, props);\n\t\telem\n\t\t\t.show()\n\t\t\t.css({\n\t\t\t\tbackgroundImage: 'none',\n\t\t\t\tbackgroundColor: o.options.color || '#ffff99'\n\t\t\t})\n\t\t\t.animate(animation, {\n\t\t\t\tqueue: false,\n\t\t\t\tduration: o.duration,\n\t\t\t\teasing: o.options.easing,\n\t\t\t\tcomplete: function() {\n\t\t\t\t\t(mode == 'hide' && elem.hide());\n\t\t\t\t\t$.effects.restore(elem, props);\n\t\t\t\t\t(mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter'));\n\t\t\t\t\t(o.callback && o.callback.apply(this, arguments));\n\t\t\t\t\telem.dequeue();\n\t\t\t\t}\n\t\t\t});\n\t});\n};\n\n})(jQuery);\n"
  },
  {
    "path": "src/lib/jquery-ui-1.8.6/js/jquery-ui-1.8.6.js",
    "content": "/*!\n * jQuery UI 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI\n */\n(function( $, undefined ) {\n\n// prevent duplicate loading\n// this is only a problem because we proxy existing functions\n// and we don't want to double proxy them\n$.ui = $.ui || {};\nif ( $.ui.version ) {\n\treturn;\n}\n\n$.extend( $.ui, {\n\tversion: \"1.8.6\",\n\n\tkeyCode: {\n\t\tALT: 18,\n\t\tBACKSPACE: 8,\n\t\tCAPS_LOCK: 20,\n\t\tCOMMA: 188,\n\t\tCOMMAND: 91,\n\t\tCOMMAND_LEFT: 91, // COMMAND\n\t\tCOMMAND_RIGHT: 93,\n\t\tCONTROL: 17,\n\t\tDELETE: 46,\n\t\tDOWN: 40,\n\t\tEND: 35,\n\t\tENTER: 13,\n\t\tESCAPE: 27,\n\t\tHOME: 36,\n\t\tINSERT: 45,\n\t\tLEFT: 37,\n\t\tMENU: 93, // COMMAND_RIGHT\n\t\tNUMPAD_ADD: 107,\n\t\tNUMPAD_DECIMAL: 110,\n\t\tNUMPAD_DIVIDE: 111,\n\t\tNUMPAD_ENTER: 108,\n\t\tNUMPAD_MULTIPLY: 106,\n\t\tNUMPAD_SUBTRACT: 109,\n\t\tPAGE_DOWN: 34,\n\t\tPAGE_UP: 33,\n\t\tPERIOD: 190,\n\t\tRIGHT: 39,\n\t\tSHIFT: 16,\n\t\tSPACE: 32,\n\t\tTAB: 9,\n\t\tUP: 38,\n\t\tWINDOWS: 91 // COMMAND\n\t}\n});\n\n// plugins\n$.fn.extend({\n\t_focus: $.fn.focus,\n\tfocus: function( delay, fn ) {\n\t\treturn typeof delay === \"number\" ?\n\t\t\tthis.each(function() {\n\t\t\t\tvar elem = this;\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t$( elem ).focus();\n\t\t\t\t\tif ( fn ) {\n\t\t\t\t\t\tfn.call( elem );\n\t\t\t\t\t}\n\t\t\t\t}, delay );\n\t\t\t}) :\n\t\t\tthis._focus.apply( this, arguments );\n\t},\n\n\tscrollParent: function() {\n\t\tvar scrollParent;\n\t\tif (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {\n\t\t\tscrollParent = this.parents().filter(function() {\n\t\t\t\treturn (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));\n\t\t\t}).eq(0);\n\t\t} else {\n\t\t\tscrollParent = this.parents().filter(function() {\n\t\t\t\treturn (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));\n\t\t\t}).eq(0);\n\t\t}\n\n\t\treturn (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;\n\t},\n\n\tzIndex: function( zIndex ) {\n\t\tif ( zIndex !== undefined ) {\n\t\t\treturn this.css( \"zIndex\", zIndex );\n\t\t}\n\n\t\tif ( this.length ) {\n\t\t\tvar elem = $( this[ 0 ] ), position, value;\n\t\t\twhile ( elem.length && elem[ 0 ] !== document ) {\n\t\t\t\t// Ignore z-index if position is set to a value where z-index is ignored by the browser\n\t\t\t\t// This makes behavior of this function consistent across browsers\n\t\t\t\t// WebKit always returns auto if the element is positioned\n\t\t\t\tposition = elem.css( \"position\" );\n\t\t\t\tif ( position === \"absolute\" || position === \"relative\" || position === \"fixed\" ) {\n\t\t\t\t\t// IE returns 0 when zIndex is not specified\n\t\t\t\t\t// other browsers return a string\n\t\t\t\t\t// we ignore the case of nested elements with an explicit value of 0\n\t\t\t\t\t// <div style=\"z-index: -10;\"><div style=\"z-index: 0;\"></div></div>\n\t\t\t\t\tvalue = parseInt( elem.css( \"zIndex\" ), 10 );\n\t\t\t\t\tif ( !isNaN( value ) && value !== 0 ) {\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telem = elem.parent();\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t},\n\n\tdisableSelection: function() {\n\t\treturn this.bind( ( $.support.selectstart ? \"selectstart\" : \"mousedown\" ) +\n\t\t\t\".ui-disableSelection\", function( event ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t});\n\t},\n\n\tenableSelection: function() {\n\t\treturn this.unbind( \".ui-disableSelection\" );\n\t}\n});\n\n$.each( [ \"Width\", \"Height\" ], function( i, name ) {\n\tvar side = name === \"Width\" ? [ \"Left\", \"Right\" ] : [ \"Top\", \"Bottom\" ],\n\t\ttype = name.toLowerCase(),\n\t\torig = {\n\t\t\tinnerWidth: $.fn.innerWidth,\n\t\t\tinnerHeight: $.fn.innerHeight,\n\t\t\touterWidth: $.fn.outerWidth,\n\t\t\touterHeight: $.fn.outerHeight\n\t\t};\n\n\tfunction reduce( elem, size, border, margin ) {\n\t\t$.each( side, function() {\n\t\t\tsize -= parseFloat( $.curCSS( elem, \"padding\" + this, true) ) || 0;\n\t\t\tif ( border ) {\n\t\t\t\tsize -= parseFloat( $.curCSS( elem, \"border\" + this + \"Width\", true) ) || 0;\n\t\t\t}\n\t\t\tif ( margin ) {\n\t\t\t\tsize -= parseFloat( $.curCSS( elem, \"margin\" + this, true) ) || 0;\n\t\t\t}\n\t\t});\n\t\treturn size;\n\t}\n\n\t$.fn[ \"inner\" + name ] = function( size ) {\n\t\tif ( size === undefined ) {\n\t\t\treturn orig[ \"inner\" + name ].call( this );\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\t$( this ).css( type, reduce( this, size ) + \"px\" );\n\t\t});\n\t};\n\n\t$.fn[ \"outer\" + name] = function( size, margin ) {\n\t\tif ( typeof size !== \"number\" ) {\n\t\t\treturn orig[ \"outer\" + name ].call( this, size );\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\t$( this).css( type, reduce( this, size, true, margin ) + \"px\" );\n\t\t});\n\t};\n});\n\n// selectors\nfunction visible( element ) {\n\treturn !$( element ).parents().andSelf().filter(function() {\n\t\treturn $.curCSS( this, \"visibility\" ) === \"hidden\" ||\n\t\t\t$.expr.filters.hidden( this );\n\t}).length;\n}\n\n$.extend( $.expr[ \":\" ], {\n\tdata: function( elem, i, match ) {\n\t\treturn !!$.data( elem, match[ 3 ] );\n\t},\n\n\tfocusable: function( element ) {\n\t\tvar nodeName = element.nodeName.toLowerCase(),\n\t\t\ttabIndex = $.attr( element, \"tabindex\" );\n\t\tif ( \"area\" === nodeName ) {\n\t\t\tvar map = element.parentNode,\n\t\t\t\tmapName = map.name,\n\t\t\t\timg;\n\t\t\tif ( !element.href || !mapName || map.nodeName.toLowerCase() !== \"map\" ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\timg = $( \"img[usemap=#\" + mapName + \"]\" )[0];\n\t\t\treturn !!img && visible( img );\n\t\t}\n\t\treturn ( /input|select|textarea|button|object/.test( nodeName )\n\t\t\t? !element.disabled\n\t\t\t: \"a\" == nodeName\n\t\t\t\t? element.href || !isNaN( tabIndex )\n\t\t\t\t: !isNaN( tabIndex ))\n\t\t\t// the element and all of its ancestors must be visible\n\t\t\t&& visible( element );\n\t},\n\n\ttabbable: function( element ) {\n\t\tvar tabIndex = $.attr( element, \"tabindex\" );\n\t\treturn ( isNaN( tabIndex ) || tabIndex >= 0 ) && $( element ).is( \":focusable\" );\n\t}\n});\n\n// support\n$(function() {\n\tvar body = document.body,\n\t\tdiv = body.appendChild( div = document.createElement( \"div\" ) );\n\n\t$.extend( div.style, {\n\t\tminHeight: \"100px\",\n\t\theight: \"auto\",\n\t\tpadding: 0,\n\t\tborderWidth: 0\n\t});\n\n\t$.support.minHeight = div.offsetHeight === 100;\n\t$.support.selectstart = \"onselectstart\" in div;\n\n\t// set display to none to avoid a layout bug in IE\n\t// http://dev.jquery.com/ticket/4014\n\tbody.removeChild( div ).style.display = \"none\";\n});\n\n\n\n\n\n// deprecated\n$.extend( $.ui, {\n\t// $.ui.plugin is deprecated.  Use the proxy pattern instead.\n\tplugin: {\n\t\tadd: function( module, option, set ) {\n\t\t\tvar proto = $.ui[ module ].prototype;\n\t\t\tfor ( var i in set ) {\n\t\t\t\tproto.plugins[ i ] = proto.plugins[ i ] || [];\n\t\t\t\tproto.plugins[ i ].push( [ option, set[ i ] ] );\n\t\t\t}\n\t\t},\n\t\tcall: function( instance, name, args ) {\n\t\t\tvar set = instance.plugins[ name ];\n\t\t\tif ( !set || !instance.element[ 0 ].parentNode ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\tfor ( var i = 0; i < set.length; i++ ) {\n\t\t\t\tif ( instance.options[ set[ i ][ 0 ] ] ) {\n\t\t\t\t\tset[ i ][ 1 ].apply( instance.element, args );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\t\n\t// will be deprecated when we switch to jQuery 1.4 - use jQuery.contains()\n\tcontains: function( a, b ) {\n\t\treturn document.compareDocumentPosition ?\n\t\t\ta.compareDocumentPosition( b ) & 16 :\n\t\t\ta !== b && a.contains( b );\n\t},\n\t\n\t// only used by resizable\n\thasScroll: function( el, a ) {\n\t\n\t\t//If overflow is hidden, the element might have extra content, but the user wants to hide it\n\t\tif ( $( el ).css( \"overflow\" ) === \"hidden\") {\n\t\t\treturn false;\n\t\t}\n\t\n\t\tvar scroll = ( a && a === \"left\" ) ? \"scrollLeft\" : \"scrollTop\",\n\t\t\thas = false;\n\t\n\t\tif ( el[ scroll ] > 0 ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t// TODO: determine which cases actually cause this to happen\n\t\t// if the element doesn't have the scroll set, see if it's possible to\n\t\t// set the scroll\n\t\tel[ scroll ] = 1;\n\t\thas = ( el[ scroll ] > 0 );\n\t\tel[ scroll ] = 0;\n\t\treturn has;\n\t},\n\t\n\t// these are odd functions, fix the API or move into individual plugins\n\tisOverAxis: function( x, reference, size ) {\n\t\t//Determines when x coordinate is over \"b\" element axis\n\t\treturn ( x > reference ) && ( x < ( reference + size ) );\n\t},\n\tisOver: function( y, x, top, left, height, width ) {\n\t\t//Determines when x, y coordinates is over \"b\" element\n\t\treturn $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );\n\t}\n});\n\n})( jQuery );\n/*!\n * jQuery UI Widget 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Widget\n */\n(function( $, undefined ) {\n\n// jQuery 1.4+\nif ( $.cleanData ) {\n\tvar _cleanData = $.cleanData;\n\t$.cleanData = function( elems ) {\n\t\tfor ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n\t\t\t$( elem ).triggerHandler( \"remove\" );\n\t\t}\n\t\t_cleanData( elems );\n\t};\n} else {\n\tvar _remove = $.fn.remove;\n\t$.fn.remove = function( selector, keepData ) {\n\t\treturn this.each(function() {\n\t\t\tif ( !keepData ) {\n\t\t\t\tif ( !selector || $.filter( selector, [ this ] ).length ) {\n\t\t\t\t\t$( \"*\", this ).add( [ this ] ).each(function() {\n\t\t\t\t\t\t$( this ).triggerHandler( \"remove\" );\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn _remove.call( $(this), selector, keepData );\n\t\t});\n\t};\n}\n\n$.widget = function( name, base, prototype ) {\n\tvar namespace = name.split( \".\" )[ 0 ],\n\t\tfullName;\n\tname = name.split( \".\" )[ 1 ];\n\tfullName = namespace + \"-\" + name;\n\n\tif ( !prototype ) {\n\t\tprototype = base;\n\t\tbase = $.Widget;\n\t}\n\n\t// create selector for plugin\n\t$.expr[ \":\" ][ fullName ] = function( elem ) {\n\t\treturn !!$.data( elem, name );\n\t};\n\n\t$[ namespace ] = $[ namespace ] || {};\n\t$[ namespace ][ name ] = function( options, element ) {\n\t\t// allow instantiation without initializing for simple inheritance\n\t\tif ( arguments.length ) {\n\t\t\tthis._createWidget( options, element );\n\t\t}\n\t};\n\n\tvar basePrototype = new base();\n\t// we need to make the options hash a property directly on the new instance\n\t// otherwise we'll modify the options hash on the prototype that we're\n\t// inheriting from\n//\t$.each( basePrototype, function( key, val ) {\n//\t\tif ( $.isPlainObject(val) ) {\n//\t\t\tbasePrototype[ key ] = $.extend( {}, val );\n//\t\t}\n//\t});\n\tbasePrototype.options = $.extend( true, {}, basePrototype.options );\n\t$[ namespace ][ name ].prototype = $.extend( true, basePrototype, {\n\t\tnamespace: namespace,\n\t\twidgetName: name,\n\t\twidgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,\n\t\twidgetBaseClass: fullName\n\t}, prototype );\n\n\t$.widget.bridge( name, $[ namespace ][ name ] );\n};\n\n$.widget.bridge = function( name, object ) {\n\t$.fn[ name ] = function( options ) {\n\t\tvar isMethodCall = typeof options === \"string\",\n\t\t\targs = Array.prototype.slice.call( arguments, 1 ),\n\t\t\treturnValue = this;\n\n\t\t// allow multiple hashes to be passed on init\n\t\toptions = !isMethodCall && args.length ?\n\t\t\t$.extend.apply( null, [ true, options ].concat(args) ) :\n\t\t\toptions;\n\n\t\t// prevent calls to internal methods\n\t\tif ( isMethodCall && options.charAt( 0 ) === \"_\" ) {\n\t\t\treturn returnValue;\n\t\t}\n\n\t\tif ( isMethodCall ) {\n\t\t\tthis.each(function() {\n\t\t\t\tvar instance = $.data( this, name ),\n\t\t\t\t\tmethodValue = instance && $.isFunction( instance[options] ) ?\n\t\t\t\t\t\tinstance[ options ].apply( instance, args ) :\n\t\t\t\t\t\tinstance;\n\t\t\t\t// TODO: add this back in 1.9 and use $.error() (see #5972)\n//\t\t\t\tif ( !instance ) {\n//\t\t\t\t\tthrow \"cannot call methods on \" + name + \" prior to initialization; \" +\n//\t\t\t\t\t\t\"attempted to call method '\" + options + \"'\";\n//\t\t\t\t}\n//\t\t\t\tif ( !$.isFunction( instance[options] ) ) {\n//\t\t\t\t\tthrow \"no such method '\" + options + \"' for \" + name + \" widget instance\";\n//\t\t\t\t}\n//\t\t\t\tvar methodValue = instance[ options ].apply( instance, args );\n\t\t\t\tif ( methodValue !== instance && methodValue !== undefined ) {\n\t\t\t\t\treturnValue = methodValue;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\tthis.each(function() {\n\t\t\t\tvar instance = $.data( this, name );\n\t\t\t\tif ( instance ) {\n\t\t\t\t\tinstance.option( options || {} )._init();\n\t\t\t\t} else {\n\t\t\t\t\t$.data( this, name, new object( options, this ) );\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn returnValue;\n\t};\n};\n\n$.Widget = function( options, element ) {\n\t// allow instantiation without initializing for simple inheritance\n\tif ( arguments.length ) {\n\t\tthis._createWidget( options, element );\n\t}\n};\n\n$.Widget.prototype = {\n\twidgetName: \"widget\",\n\twidgetEventPrefix: \"\",\n\toptions: {\n\t\tdisabled: false\n\t},\n\t_createWidget: function( options, element ) {\n\t\t// $.widget.bridge stores the plugin instance, but we do it anyway\n\t\t// so that it's stored even before the _create function runs\n\t\t$.data( element, this.widgetName, this );\n\t\tthis.element = $( element );\n\t\tthis.options = $.extend( true, {},\n\t\t\tthis.options,\n\t\t\tthis._getCreateOptions(),\n\t\t\toptions );\n\n\t\tvar self = this;\n\t\tthis.element.bind( \"remove.\" + this.widgetName, function() {\n\t\t\tself.destroy();\n\t\t});\n\n\t\tthis._create();\n\t\tthis._trigger( \"create\" );\n\t\tthis._init();\n\t},\n\t_getCreateOptions: function() {\n\t\treturn $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];\n\t},\n\t_create: function() {},\n\t_init: function() {},\n\n\tdestroy: function() {\n\t\tthis.element\n\t\t\t.unbind( \".\" + this.widgetName )\n\t\t\t.removeData( this.widgetName );\n\t\tthis.widget()\n\t\t\t.unbind( \".\" + this.widgetName )\n\t\t\t.removeAttr( \"aria-disabled\" )\n\t\t\t.removeClass(\n\t\t\t\tthis.widgetBaseClass + \"-disabled \" +\n\t\t\t\t\"ui-state-disabled\" );\n\t},\n\n\twidget: function() {\n\t\treturn this.element;\n\t},\n\n\toption: function( key, value ) {\n\t\tvar options = key;\n\n\t\tif ( arguments.length === 0 ) {\n\t\t\t// don't return a reference to the internal hash\n\t\t\treturn $.extend( {}, this.options );\n\t\t}\n\n\t\tif  (typeof key === \"string\" ) {\n\t\t\tif ( value === undefined ) {\n\t\t\t\treturn this.options[ key ];\n\t\t\t}\n\t\t\toptions = {};\n\t\t\toptions[ key ] = value;\n\t\t}\n\n\t\tthis._setOptions( options );\n\n\t\treturn this;\n\t},\n\t_setOptions: function( options ) {\n\t\tvar self = this;\n\t\t$.each( options, function( key, value ) {\n\t\t\tself._setOption( key, value );\n\t\t});\n\n\t\treturn this;\n\t},\n\t_setOption: function( key, value ) {\n\t\tthis.options[ key ] = value;\n\n\t\tif ( key === \"disabled\" ) {\n\t\t\tthis.widget()\n\t\t\t\t[ value ? \"addClass\" : \"removeClass\"](\n\t\t\t\t\tthis.widgetBaseClass + \"-disabled\" + \" \" +\n\t\t\t\t\t\"ui-state-disabled\" )\n\t\t\t\t.attr( \"aria-disabled\", value );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tenable: function() {\n\t\treturn this._setOption( \"disabled\", false );\n\t},\n\tdisable: function() {\n\t\treturn this._setOption( \"disabled\", true );\n\t},\n\n\t_trigger: function( type, event, data ) {\n\t\tvar callback = this.options[ type ];\n\n\t\tevent = $.Event( event );\n\t\tevent.type = ( type === this.widgetEventPrefix ?\n\t\t\ttype :\n\t\t\tthis.widgetEventPrefix + type ).toLowerCase();\n\t\tdata = data || {};\n\n\t\t// copy original event properties over to the new event\n\t\t// this would happen if we could call $.event.fix instead of $.Event\n\t\t// but we don't have a way to force an event to be fixed multiple times\n\t\tif ( event.originalEvent ) {\n\t\t\tfor ( var i = $.event.props.length, prop; i; ) {\n\t\t\t\tprop = $.event.props[ --i ];\n\t\t\t\tevent[ prop ] = event.originalEvent[ prop ];\n\t\t\t}\n\t\t}\n\n\t\tthis.element.trigger( event, data );\n\n\t\treturn !( $.isFunction(callback) &&\n\t\t\tcallback.call( this.element[0], event, data ) === false ||\n\t\t\tevent.isDefaultPrevented() );\n\t}\n};\n\n})( jQuery );\n/*!\n * jQuery UI Mouse 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Mouse\n *\n * Depends:\n *\tjquery.ui.widget.js\n */\n(function( $, undefined ) {\n\n$.widget(\"ui.mouse\", {\n\toptions: {\n\t\tcancel: ':input,option',\n\t\tdistance: 1,\n\t\tdelay: 0\n\t},\n\t_mouseInit: function() {\n\t\tvar self = this;\n\n\t\tthis.element\n\t\t\t.bind('mousedown.'+this.widgetName, function(event) {\n\t\t\t\treturn self._mouseDown(event);\n\t\t\t})\n\t\t\t.bind('click.'+this.widgetName, function(event) {\n\t\t\t\tif(self._preventClickEvent) {\n\t\t\t\t\tself._preventClickEvent = false;\n\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\n\t\tthis.started = false;\n\t},\n\n\t// TODO: make sure destroying one instance of mouse doesn't mess with\n\t// other instances of mouse\n\t_mouseDestroy: function() {\n\t\tthis.element.unbind('.'+this.widgetName);\n\t},\n\n\t_mouseDown: function(event) {\n\t\t// don't let more than one widget handle mouseStart\n\t\t// TODO: figure out why we have to use originalEvent\n\t\tevent.originalEvent = event.originalEvent || {};\n\t\tif (event.originalEvent.mouseHandled) { return; }\n\n\t\t// we may have missed mouseup (out of window)\n\t\t(this._mouseStarted && this._mouseUp(event));\n\n\t\tthis._mouseDownEvent = event;\n\n\t\tvar self = this,\n\t\t\tbtnIsLeft = (event.which == 1),\n\t\t\telIsCancel = (typeof this.options.cancel == \"string\" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);\n\t\tif (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.mouseDelayMet = !this.options.delay;\n\t\tif (!this.mouseDelayMet) {\n\t\t\tthis._mouseDelayTimer = setTimeout(function() {\n\t\t\t\tself.mouseDelayMet = true;\n\t\t\t}, this.options.delay);\n\t\t}\n\n\t\tif (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {\n\t\t\tthis._mouseStarted = (this._mouseStart(event) !== false);\n\t\t\tif (!this._mouseStarted) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// these delegates are required to keep context\n\t\tthis._mouseMoveDelegate = function(event) {\n\t\t\treturn self._mouseMove(event);\n\t\t};\n\t\tthis._mouseUpDelegate = function(event) {\n\t\t\treturn self._mouseUp(event);\n\t\t};\n\t\t$(document)\n\t\t\t.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)\n\t\t\t.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);\n\n\t\tevent.preventDefault();\n\t\tevent.originalEvent.mouseHandled = true;\n\t\treturn true;\n\t},\n\n\t_mouseMove: function(event) {\n\t\t// IE mouseup check - mouseup happened when mouse was out of window\n\t\tif ($.browser.msie && !(document.documentMode >= 9) && !event.button) {\n\t\t\treturn this._mouseUp(event);\n\t\t}\n\n\t\tif (this._mouseStarted) {\n\t\t\tthis._mouseDrag(event);\n\t\t\treturn event.preventDefault();\n\t\t}\n\n\t\tif (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {\n\t\t\tthis._mouseStarted =\n\t\t\t\t(this._mouseStart(this._mouseDownEvent, event) !== false);\n\t\t\t(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));\n\t\t}\n\n\t\treturn !this._mouseStarted;\n\t},\n\n\t_mouseUp: function(event) {\n\t\t$(document)\n\t\t\t.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)\n\t\t\t.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);\n\n\t\tif (this._mouseStarted) {\n\t\t\tthis._mouseStarted = false;\n\t\t\tthis._preventClickEvent = (event.target == this._mouseDownEvent.target);\n\t\t\tthis._mouseStop(event);\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_mouseDistanceMet: function(event) {\n\t\treturn (Math.max(\n\t\t\t\tMath.abs(this._mouseDownEvent.pageX - event.pageX),\n\t\t\t\tMath.abs(this._mouseDownEvent.pageY - event.pageY)\n\t\t\t) >= this.options.distance\n\t\t);\n\t},\n\n\t_mouseDelayMet: function(event) {\n\t\treturn this.mouseDelayMet;\n\t},\n\n\t// These are placeholder methods, to be overriden by extending plugin\n\t_mouseStart: function(event) {},\n\t_mouseDrag: function(event) {},\n\t_mouseStop: function(event) {},\n\t_mouseCapture: function(event) { return true; }\n});\n\n})(jQuery);\n/*\n * jQuery UI Position 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Position\n */\n(function( $, undefined ) {\n\n$.ui = $.ui || {};\n\nvar horizontalPositions = /left|center|right/,\n\tverticalPositions = /top|center|bottom/,\n\tcenter = \"center\",\n\t_position = $.fn.position,\n\t_offset = $.fn.offset;\n\n$.fn.position = function( options ) {\n\tif ( !options || !options.of ) {\n\t\treturn _position.apply( this, arguments );\n\t}\n\n\t// make a copy, we don't want to modify arguments\n\toptions = $.extend( {}, options );\n\n\tvar target = $( options.of ),\n\t\ttargetElem = target[0],\n\t\tcollision = ( options.collision || \"flip\" ).split( \" \" ),\n\t\toffset = options.offset ? options.offset.split( \" \" ) : [ 0, 0 ],\n\t\ttargetWidth,\n\t\ttargetHeight,\n\t\tbasePosition;\n\n\tif ( targetElem.nodeType === 9 ) {\n\t\ttargetWidth = target.width();\n\t\ttargetHeight = target.height();\n\t\tbasePosition = { top: 0, left: 0 };\n\t// TODO: use $.isWindow() in 1.9\n\t} else if ( targetElem.setTimeout ) {\n\t\ttargetWidth = target.width();\n\t\ttargetHeight = target.height();\n\t\tbasePosition = { top: target.scrollTop(), left: target.scrollLeft() };\n\t} else if ( targetElem.preventDefault ) {\n\t\t// force left top to allow flipping\n\t\toptions.at = \"left top\";\n\t\ttargetWidth = targetHeight = 0;\n\t\tbasePosition = { top: options.of.pageY, left: options.of.pageX };\n\t} else {\n\t\ttargetWidth = target.outerWidth();\n\t\ttargetHeight = target.outerHeight();\n\t\tbasePosition = target.offset();\n\t}\n\n\t// force my and at to have valid horizontal and veritcal positions\n\t// if a value is missing or invalid, it will be converted to center \n\t$.each( [ \"my\", \"at\" ], function() {\n\t\tvar pos = ( options[this] || \"\" ).split( \" \" );\n\t\tif ( pos.length === 1) {\n\t\t\tpos = horizontalPositions.test( pos[0] ) ?\n\t\t\t\tpos.concat( [center] ) :\n\t\t\t\tverticalPositions.test( pos[0] ) ?\n\t\t\t\t\t[ center ].concat( pos ) :\n\t\t\t\t\t[ center, center ];\n\t\t}\n\t\tpos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center;\n\t\tpos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center;\n\t\toptions[ this ] = pos;\n\t});\n\n\t// normalize collision option\n\tif ( collision.length === 1 ) {\n\t\tcollision[ 1 ] = collision[ 0 ];\n\t}\n\n\t// normalize offset option\n\toffset[ 0 ] = parseInt( offset[0], 10 ) || 0;\n\tif ( offset.length === 1 ) {\n\t\toffset[ 1 ] = offset[ 0 ];\n\t}\n\toffset[ 1 ] = parseInt( offset[1], 10 ) || 0;\n\n\tif ( options.at[0] === \"right\" ) {\n\t\tbasePosition.left += targetWidth;\n\t} else if (options.at[0] === center ) {\n\t\tbasePosition.left += targetWidth / 2;\n\t}\n\n\tif ( options.at[1] === \"bottom\" ) {\n\t\tbasePosition.top += targetHeight;\n\t} else if ( options.at[1] === center ) {\n\t\tbasePosition.top += targetHeight / 2;\n\t}\n\n\tbasePosition.left += offset[ 0 ];\n\tbasePosition.top += offset[ 1 ];\n\n\treturn this.each(function() {\n\t\tvar elem = $( this ),\n\t\t\telemWidth = elem.outerWidth(),\n\t\t\telemHeight = elem.outerHeight(),\n\t\t\tmarginLeft = parseInt( $.curCSS( this, \"marginLeft\", true ) ) || 0,\n\t\t\tmarginTop = parseInt( $.curCSS( this, \"marginTop\", true ) ) || 0,\n\t\t\tcollisionWidth = elemWidth + marginLeft +\n\t\t\t\tparseInt( $.curCSS( this, \"marginRight\", true ) ) || 0,\n\t\t\tcollisionHeight = elemHeight + marginTop +\n\t\t\t\tparseInt( $.curCSS( this, \"marginBottom\", true ) ) || 0,\n\t\t\tposition = $.extend( {}, basePosition ),\n\t\t\tcollisionPosition;\n\n\t\tif ( options.my[0] === \"right\" ) {\n\t\t\tposition.left -= elemWidth;\n\t\t} else if ( options.my[0] === center ) {\n\t\t\tposition.left -= elemWidth / 2;\n\t\t}\n\n\t\tif ( options.my[1] === \"bottom\" ) {\n\t\t\tposition.top -= elemHeight;\n\t\t} else if ( options.my[1] === center ) {\n\t\t\tposition.top -= elemHeight / 2;\n\t\t}\n\n\t\t// prevent fractions (see #5280)\n\t\tposition.left = parseInt( position.left );\n\t\tposition.top = parseInt( position.top );\n\n\t\tcollisionPosition = {\n\t\t\tleft: position.left - marginLeft,\n\t\t\ttop: position.top - marginTop\n\t\t};\n\n\t\t$.each( [ \"left\", \"top\" ], function( i, dir ) {\n\t\t\tif ( $.ui.position[ collision[i] ] ) {\n\t\t\t\t$.ui.position[ collision[i] ][ dir ]( position, {\n\t\t\t\t\ttargetWidth: targetWidth,\n\t\t\t\t\ttargetHeight: targetHeight,\n\t\t\t\t\telemWidth: elemWidth,\n\t\t\t\t\telemHeight: elemHeight,\n\t\t\t\t\tcollisionPosition: collisionPosition,\n\t\t\t\t\tcollisionWidth: collisionWidth,\n\t\t\t\t\tcollisionHeight: collisionHeight,\n\t\t\t\t\toffset: offset,\n\t\t\t\t\tmy: options.my,\n\t\t\t\t\tat: options.at\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\tif ( $.fn.bgiframe ) {\n\t\t\telem.bgiframe();\n\t\t}\n\t\telem.offset( $.extend( position, { using: options.using } ) );\n\t});\n};\n\n$.ui.position = {\n\tfit: {\n\t\tleft: function( position, data ) {\n\t\t\tvar win = $( window ),\n\t\t\t\tover = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft();\n\t\t\tposition.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left );\n\t\t},\n\t\ttop: function( position, data ) {\n\t\t\tvar win = $( window ),\n\t\t\t\tover = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop();\n\t\t\tposition.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top );\n\t\t}\n\t},\n\n\tflip: {\n\t\tleft: function( position, data ) {\n\t\t\tif ( data.at[0] === center ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar win = $( window ),\n\t\t\t\tover = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(),\n\t\t\t\tmyOffset = data.my[ 0 ] === \"left\" ?\n\t\t\t\t\t-data.elemWidth :\n\t\t\t\t\tdata.my[ 0 ] === \"right\" ?\n\t\t\t\t\t\tdata.elemWidth :\n\t\t\t\t\t\t0,\n\t\t\t\tatOffset = data.at[ 0 ] === \"left\" ?\n\t\t\t\t\tdata.targetWidth :\n\t\t\t\t\t-data.targetWidth,\n\t\t\t\toffset = -2 * data.offset[ 0 ];\n\t\t\tposition.left += data.collisionPosition.left < 0 ?\n\t\t\t\tmyOffset + atOffset + offset :\n\t\t\t\tover > 0 ?\n\t\t\t\t\tmyOffset + atOffset + offset :\n\t\t\t\t\t0;\n\t\t},\n\t\ttop: function( position, data ) {\n\t\t\tif ( data.at[1] === center ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar win = $( window ),\n\t\t\t\tover = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(),\n\t\t\t\tmyOffset = data.my[ 1 ] === \"top\" ?\n\t\t\t\t\t-data.elemHeight :\n\t\t\t\t\tdata.my[ 1 ] === \"bottom\" ?\n\t\t\t\t\t\tdata.elemHeight :\n\t\t\t\t\t\t0,\n\t\t\t\tatOffset = data.at[ 1 ] === \"top\" ?\n\t\t\t\t\tdata.targetHeight :\n\t\t\t\t\t-data.targetHeight,\n\t\t\t\toffset = -2 * data.offset[ 1 ];\n\t\t\tposition.top += data.collisionPosition.top < 0 ?\n\t\t\t\tmyOffset + atOffset + offset :\n\t\t\t\tover > 0 ?\n\t\t\t\t\tmyOffset + atOffset + offset :\n\t\t\t\t\t0;\n\t\t}\n\t}\n};\n\n// offset setter from jQuery 1.4\nif ( !$.offset.setOffset ) {\n\t$.offset.setOffset = function( elem, options ) {\n\t\t// set position first, in-case top/left are set even on static elem\n\t\tif ( /static/.test( $.curCSS( elem, \"position\" ) ) ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\t\tvar curElem   = $( elem ),\n\t\t\tcurOffset = curElem.offset(),\n\t\t\tcurTop    = parseInt( $.curCSS( elem, \"top\",  true ), 10 ) || 0,\n\t\t\tcurLeft   = parseInt( $.curCSS( elem, \"left\", true ), 10)  || 0,\n\t\t\tprops     = {\n\t\t\t\ttop:  (options.top  - curOffset.top)  + curTop,\n\t\t\t\tleft: (options.left - curOffset.left) + curLeft\n\t\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\t$.fn.offset = function( options ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( !elem || !elem.ownerDocument ) { return null; }\n\t\tif ( options ) { \n\t\t\treturn this.each(function() {\n\t\t\t\t$.offset.setOffset( this, options );\n\t\t\t});\n\t\t}\n\t\treturn _offset.call( this );\n\t};\n}\n\n}( jQuery ));\n/*\n * jQuery UI Draggable 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Draggables\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.mouse.js\n *\tjquery.ui.widget.js\n */\n(function( $, undefined ) {\n\n$.widget(\"ui.draggable\", $.ui.mouse, {\n\twidgetEventPrefix: \"drag\",\n\toptions: {\n\t\taddClasses: true,\n\t\tappendTo: \"parent\",\n\t\taxis: false,\n\t\tconnectToSortable: false,\n\t\tcontainment: false,\n\t\tcursor: \"auto\",\n\t\tcursorAt: false,\n\t\tgrid: false,\n\t\thandle: false,\n\t\thelper: \"original\",\n\t\tiframeFix: false,\n\t\topacity: false,\n\t\trefreshPositions: false,\n\t\trevert: false,\n\t\trevertDuration: 500,\n\t\tscope: \"default\",\n\t\tscroll: true,\n\t\tscrollSensitivity: 20,\n\t\tscrollSpeed: 20,\n\t\tsnap: false,\n\t\tsnapMode: \"both\",\n\t\tsnapTolerance: 20,\n\t\tstack: false,\n\t\tzIndex: false\n\t},\n\t_create: function() {\n\n\t\tif (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css(\"position\")))\n\t\t\tthis.element[0].style.position = 'relative';\n\n\t\t(this.options.addClasses && this.element.addClass(\"ui-draggable\"));\n\t\t(this.options.disabled && this.element.addClass(\"ui-draggable-disabled\"));\n\n\t\tthis._mouseInit();\n\n\t},\n\n\tdestroy: function() {\n\t\tif(!this.element.data('draggable')) return;\n\t\tthis.element\n\t\t\t.removeData(\"draggable\")\n\t\t\t.unbind(\".draggable\")\n\t\t\t.removeClass(\"ui-draggable\"\n\t\t\t\t+ \" ui-draggable-dragging\"\n\t\t\t\t+ \" ui-draggable-disabled\");\n\t\tthis._mouseDestroy();\n\n\t\treturn this;\n\t},\n\n\t_mouseCapture: function(event) {\n\n\t\tvar o = this.options;\n\n\t\t// among others, prevent a drag on a resizable-handle\n\t\tif (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))\n\t\t\treturn false;\n\n\t\t//Quit if we're not on a valid handle\n\t\tthis.handle = this._getHandle(event);\n\t\tif (!this.handle)\n\t\t\treturn false;\n\n\t\treturn true;\n\n\t},\n\n\t_mouseStart: function(event) {\n\n\t\tvar o = this.options;\n\n\t\t//Create and append the visible helper\n\t\tthis.helper = this._createHelper(event);\n\n\t\t//Cache the helper size\n\t\tthis._cacheHelperProportions();\n\n\t\t//If ddmanager is used for droppables, set the global draggable\n\t\tif($.ui.ddmanager)\n\t\t\t$.ui.ddmanager.current = this;\n\n\t\t/*\n\t\t * - Position generation -\n\t\t * This block generates everything position related - it's the core of draggables.\n\t\t */\n\n\t\t//Cache the margins of the original element\n\t\tthis._cacheMargins();\n\n\t\t//Store the helper's css position\n\t\tthis.cssPosition = this.helper.css(\"position\");\n\t\tthis.scrollParent = this.helper.scrollParent();\n\n\t\t//The element's absolute position on the page minus margins\n\t\tthis.offset = this.positionAbs = this.element.offset();\n\t\tthis.offset = {\n\t\t\ttop: this.offset.top - this.margins.top,\n\t\t\tleft: this.offset.left - this.margins.left\n\t\t};\n\n\t\t$.extend(this.offset, {\n\t\t\tclick: { //Where the click happened, relative to the element\n\t\t\t\tleft: event.pageX - this.offset.left,\n\t\t\t\ttop: event.pageY - this.offset.top\n\t\t\t},\n\t\t\tparent: this._getParentOffset(),\n\t\t\trelative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper\n\t\t});\n\n\t\t//Generate the original position\n\t\tthis.originalPosition = this.position = this._generatePosition(event);\n\t\tthis.originalPageX = event.pageX;\n\t\tthis.originalPageY = event.pageY;\n\n\t\t//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied\n\t\t(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));\n\n\t\t//Set a containment if given in the options\n\t\tif(o.containment)\n\t\t\tthis._setContainment();\n\n\t\t//Trigger event + callbacks\n\t\tif(this._trigger(\"start\", event) === false) {\n\t\t\tthis._clear();\n\t\t\treturn false;\n\t\t}\n\n\t\t//Recache the helper size\n\t\tthis._cacheHelperProportions();\n\n\t\t//Prepare the droppable offsets\n\t\tif ($.ui.ddmanager && !o.dropBehaviour)\n\t\t\t$.ui.ddmanager.prepareOffsets(this, event);\n\n\t\tthis.helper.addClass(\"ui-draggable-dragging\");\n\t\tthis._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position\n\t\treturn true;\n\t},\n\n\t_mouseDrag: function(event, noPropagation) {\n\n\t\t//Compute the helpers position\n\t\tthis.position = this._generatePosition(event);\n\t\tthis.positionAbs = this._convertPositionTo(\"absolute\");\n\n\t\t//Call plugins and callbacks and use the resulting position if something is returned\n\t\tif (!noPropagation) {\n\t\t\tvar ui = this._uiHash();\n\t\t\tif(this._trigger('drag', event, ui) === false) {\n\t\t\t\tthis._mouseUp({});\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis.position = ui.position;\n\t\t}\n\n\t\tif(!this.options.axis || this.options.axis != \"y\") this.helper[0].style.left = this.position.left+'px';\n\t\tif(!this.options.axis || this.options.axis != \"x\") this.helper[0].style.top = this.position.top+'px';\n\t\tif($.ui.ddmanager) $.ui.ddmanager.drag(this, event);\n\n\t\treturn false;\n\t},\n\n\t_mouseStop: function(event) {\n\n\t\t//If we are using droppables, inform the manager about the drop\n\t\tvar dropped = false;\n\t\tif ($.ui.ddmanager && !this.options.dropBehaviour)\n\t\t\tdropped = $.ui.ddmanager.drop(this, event);\n\n\t\t//if a drop comes from outside (a sortable)\n\t\tif(this.dropped) {\n\t\t\tdropped = this.dropped;\n\t\t\tthis.dropped = false;\n\t\t}\n\t\t\n\t\t//if the original element is removed, don't bother to continue\n\t\tif(!this.element[0] || !this.element[0].parentNode)\n\t\t\treturn false;\n\n\t\tif((this.options.revert == \"invalid\" && !dropped) || (this.options.revert == \"valid\" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {\n\t\t\tvar self = this;\n\t\t\t$(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {\n\t\t\t\tif(self._trigger(\"stop\", event) !== false) {\n\t\t\t\t\tself._clear();\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\tif(this._trigger(\"stop\", event) !== false) {\n\t\t\t\tthis._clear();\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t},\n\t\n\tcancel: function() {\n\t\t\n\t\tif(this.helper.is(\".ui-draggable-dragging\")) {\n\t\t\tthis._mouseUp({});\n\t\t} else {\n\t\t\tthis._clear();\n\t\t}\n\t\t\n\t\treturn this;\n\t\t\n\t},\n\n\t_getHandle: function(event) {\n\n\t\tvar handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;\n\t\t$(this.options.handle, this.element)\n\t\t\t.find(\"*\")\n\t\t\t.andSelf()\n\t\t\t.each(function() {\n\t\t\t\tif(this == event.target) handle = true;\n\t\t\t});\n\n\t\treturn handle;\n\n\t},\n\n\t_createHelper: function(event) {\n\n\t\tvar o = this.options;\n\t\tvar helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element);\n\n\t\tif(!helper.parents('body').length)\n\t\t\thelper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));\n\n\t\tif(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css(\"position\")))\n\t\t\thelper.css(\"position\", \"absolute\");\n\n\t\treturn helper;\n\n\t},\n\n\t_adjustOffsetFromHelper: function(obj) {\n\t\tif (typeof obj == 'string') {\n\t\t\tobj = obj.split(' ');\n\t\t}\n\t\tif ($.isArray(obj)) {\n\t\t\tobj = {left: +obj[0], top: +obj[1] || 0};\n\t\t}\n\t\tif ('left' in obj) {\n\t\t\tthis.offset.click.left = obj.left + this.margins.left;\n\t\t}\n\t\tif ('right' in obj) {\n\t\t\tthis.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;\n\t\t}\n\t\tif ('top' in obj) {\n\t\t\tthis.offset.click.top = obj.top + this.margins.top;\n\t\t}\n\t\tif ('bottom' in obj) {\n\t\t\tthis.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;\n\t\t}\n\t},\n\n\t_getParentOffset: function() {\n\n\t\t//Get the offsetParent and cache its position\n\t\tthis.offsetParent = this.helper.offsetParent();\n\t\tvar po = this.offsetParent.offset();\n\n\t\t// This is a special case where we need to modify a offset calculated on start, since the following happened:\n\t\t// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent\n\t\t// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that\n\t\t//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag\n\t\tif(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {\n\t\t\tpo.left += this.scrollParent.scrollLeft();\n\t\t\tpo.top += this.scrollParent.scrollTop();\n\t\t}\n\n\t\tif((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information\n\t\t|| (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix\n\t\t\tpo = { top: 0, left: 0 };\n\n\t\treturn {\n\t\t\ttop: po.top + (parseInt(this.offsetParent.css(\"borderTopWidth\"),10) || 0),\n\t\t\tleft: po.left + (parseInt(this.offsetParent.css(\"borderLeftWidth\"),10) || 0)\n\t\t};\n\n\t},\n\n\t_getRelativeOffset: function() {\n\n\t\tif(this.cssPosition == \"relative\") {\n\t\t\tvar p = this.element.position();\n\t\t\treturn {\n\t\t\t\ttop: p.top - (parseInt(this.helper.css(\"top\"),10) || 0) + this.scrollParent.scrollTop(),\n\t\t\t\tleft: p.left - (parseInt(this.helper.css(\"left\"),10) || 0) + this.scrollParent.scrollLeft()\n\t\t\t};\n\t\t} else {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t},\n\n\t_cacheMargins: function() {\n\t\tthis.margins = {\n\t\t\tleft: (parseInt(this.element.css(\"marginLeft\"),10) || 0),\n\t\t\ttop: (parseInt(this.element.css(\"marginTop\"),10) || 0)\n\t\t};\n\t},\n\n\t_cacheHelperProportions: function() {\n\t\tthis.helperProportions = {\n\t\t\twidth: this.helper.outerWidth(),\n\t\t\theight: this.helper.outerHeight()\n\t\t};\n\t},\n\n\t_setContainment: function() {\n\n\t\tvar o = this.options;\n\t\tif(o.containment == 'parent') o.containment = this.helper[0].parentNode;\n\t\tif(o.containment == 'document' || o.containment == 'window') this.containment = [\n\t\t\t0 - this.offset.relative.left - this.offset.parent.left,\n\t\t\t0 - this.offset.relative.top - this.offset.parent.top,\n\t\t\t$(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,\n\t\t\t($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top\n\t\t];\n\n\t\tif(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {\n\t\t\tvar ce = $(o.containment)[0]; if(!ce) return;\n\t\t\tvar co = $(o.containment).offset();\n\t\t\tvar over = ($(ce).css(\"overflow\") != 'hidden');\n\n\t\t\tthis.containment = [\n\t\t\t\tco.left + (parseInt($(ce).css(\"borderLeftWidth\"),10) || 0) + (parseInt($(ce).css(\"paddingLeft\"),10) || 0) - this.margins.left,\n\t\t\t\tco.top + (parseInt($(ce).css(\"borderTopWidth\"),10) || 0) + (parseInt($(ce).css(\"paddingTop\"),10) || 0) - this.margins.top,\n\t\t\t\tco.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css(\"borderLeftWidth\"),10) || 0) - (parseInt($(ce).css(\"paddingRight\"),10) || 0) - this.helperProportions.width - this.margins.left,\n\t\t\t\tco.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css(\"borderTopWidth\"),10) || 0) - (parseInt($(ce).css(\"paddingBottom\"),10) || 0) - this.helperProportions.height - this.margins.top\n\t\t\t];\n\t\t} else if(o.containment.constructor == Array) {\n\t\t\tthis.containment = o.containment;\n\t\t}\n\n\t},\n\n\t_convertPositionTo: function(d, pos) {\n\n\t\tif(!pos) pos = this.position;\n\t\tvar mod = d == \"absolute\" ? 1 : -1;\n\t\tvar o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);\n\n\t\treturn {\n\t\t\ttop: (\n\t\t\t\tpos.top\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\t+ this.offset.relative.top * mod\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\t+ this.offset.parent.top * mod\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t- ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)\n\t\t\t),\n\t\t\tleft: (\n\t\t\t\tpos.left\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\t+ this.offset.relative.left * mod\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\t+ this.offset.parent.left * mod\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t- ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)\n\t\t\t)\n\t\t};\n\n\t},\n\n\t_generatePosition: function(event) {\n\n\t\tvar o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);\n\t\tvar pageX = event.pageX;\n\t\tvar pageY = event.pageY;\n\n\t\t/*\n\t\t * - Position constraining -\n\t\t * Constrain the position to a mix of grid, containment.\n\t\t */\n\n\t\tif(this.originalPosition) { //If we are not dragging yet, we won't check for options\n\n\t\t\tif(this.containment) {\n\t\t\t\tif(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;\n\t\t\t\tif(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;\n\t\t\t\tif(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;\n\t\t\t\tif(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;\n\t\t\t}\n\n\t\t\tif(o.grid) {\n\t\t\t\tvar top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];\n\t\t\t\tpageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;\n\n\t\t\t\tvar left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];\n\t\t\t\tpageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\t\t\ttop: (\n\t\t\t\tpageY\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\t- this.offset.click.top\t\t\t\t\t\t\t\t\t\t\t\t\t// Click offset (relative to the element)\n\t\t\t\t- this.offset.relative.top\t\t\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\t- this.offset.parent.top\t\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t+ ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))\n\t\t\t),\n\t\t\tleft: (\n\t\t\t\tpageX\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\t- this.offset.click.left\t\t\t\t\t\t\t\t\t\t\t\t// Click offset (relative to the element)\n\t\t\t\t- this.offset.relative.left\t\t\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\t- this.offset.parent.left\t\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t+ ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))\n\t\t\t)\n\t\t};\n\n\t},\n\n\t_clear: function() {\n\t\tthis.helper.removeClass(\"ui-draggable-dragging\");\n\t\tif(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();\n\t\t//if($.ui.ddmanager) $.ui.ddmanager.current = null;\n\t\tthis.helper = null;\n\t\tthis.cancelHelperRemoval = false;\n\t},\n\n\t// From now on bulk stuff - mainly helpers\n\n\t_trigger: function(type, event, ui) {\n\t\tui = ui || this._uiHash();\n\t\t$.ui.plugin.call(this, type, [event, ui]);\n\t\tif(type == \"drag\") this.positionAbs = this._convertPositionTo(\"absolute\"); //The absolute position has to be recalculated after plugins\n\t\treturn $.Widget.prototype._trigger.call(this, type, event, ui);\n\t},\n\n\tplugins: {},\n\n\t_uiHash: function(event) {\n\t\treturn {\n\t\t\thelper: this.helper,\n\t\t\tposition: this.position,\n\t\t\toriginalPosition: this.originalPosition,\n\t\t\toffset: this.positionAbs\n\t\t};\n\t}\n\n});\n\n$.extend($.ui.draggable, {\n\tversion: \"1.8.6\"\n});\n\n$.ui.plugin.add(\"draggable\", \"connectToSortable\", {\n\tstart: function(event, ui) {\n\n\t\tvar inst = $(this).data(\"draggable\"), o = inst.options,\n\t\t\tuiSortable = $.extend({}, ui, { item: inst.element });\n\t\tinst.sortables = [];\n\t\t$(o.connectToSortable).each(function() {\n\t\t\tvar sortable = $.data(this, 'sortable');\n\t\t\tif (sortable && !sortable.options.disabled) {\n\t\t\t\tinst.sortables.push({\n\t\t\t\t\tinstance: sortable,\n\t\t\t\t\tshouldRevert: sortable.options.revert\n\t\t\t\t});\n\t\t\t\tsortable._refreshItems();\t//Do a one-time refresh at start to refresh the containerCache\n\t\t\t\tsortable._trigger(\"activate\", event, uiSortable);\n\t\t\t}\n\t\t});\n\n\t},\n\tstop: function(event, ui) {\n\n\t\t//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper\n\t\tvar inst = $(this).data(\"draggable\"),\n\t\t\tuiSortable = $.extend({}, ui, { item: inst.element });\n\n\t\t$.each(inst.sortables, function() {\n\t\t\tif(this.instance.isOver) {\n\n\t\t\t\tthis.instance.isOver = 0;\n\n\t\t\t\tinst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance\n\t\t\t\tthis.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)\n\n\t\t\t\t//The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'\n\t\t\t\tif(this.shouldRevert) this.instance.options.revert = true;\n\n\t\t\t\t//Trigger the stop of the sortable\n\t\t\t\tthis.instance._mouseStop(event);\n\n\t\t\t\tthis.instance.options.helper = this.instance.options._helper;\n\n\t\t\t\t//If the helper has been the original item, restore properties in the sortable\n\t\t\t\tif(inst.options.helper == 'original')\n\t\t\t\t\tthis.instance.currentItem.css({ top: 'auto', left: 'auto' });\n\n\t\t\t} else {\n\t\t\t\tthis.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance\n\t\t\t\tthis.instance._trigger(\"deactivate\", event, uiSortable);\n\t\t\t}\n\n\t\t});\n\n\t},\n\tdrag: function(event, ui) {\n\n\t\tvar inst = $(this).data(\"draggable\"), self = this;\n\n\t\tvar checkPos = function(o) {\n\t\t\tvar dyClick = this.offset.click.top, dxClick = this.offset.click.left;\n\t\t\tvar helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;\n\t\t\tvar itemHeight = o.height, itemWidth = o.width;\n\t\t\tvar itemTop = o.top, itemLeft = o.left;\n\n\t\t\treturn $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);\n\t\t};\n\n\t\t$.each(inst.sortables, function(i) {\n\t\t\t\n\t\t\t//Copy over some variables to allow calling the sortable's native _intersectsWith\n\t\t\tthis.instance.positionAbs = inst.positionAbs;\n\t\t\tthis.instance.helperProportions = inst.helperProportions;\n\t\t\tthis.instance.offset.click = inst.offset.click;\n\t\t\t\n\t\t\tif(this.instance._intersectsWith(this.instance.containerCache)) {\n\n\t\t\t\t//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once\n\t\t\t\tif(!this.instance.isOver) {\n\n\t\t\t\t\tthis.instance.isOver = 1;\n\t\t\t\t\t//Now we fake the start of dragging for the sortable instance,\n\t\t\t\t\t//by cloning the list group item, appending it to the sortable and using it as inst.currentItem\n\t\t\t\t\t//We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)\n\t\t\t\t\tthis.instance.currentItem = $(self).clone().appendTo(this.instance.element).data(\"sortable-item\", true);\n\t\t\t\t\tthis.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it\n\t\t\t\t\tthis.instance.options.helper = function() { return ui.helper[0]; };\n\n\t\t\t\t\tevent.target = this.instance.currentItem[0];\n\t\t\t\t\tthis.instance._mouseCapture(event, true);\n\t\t\t\t\tthis.instance._mouseStart(event, true, true);\n\n\t\t\t\t\t//Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes\n\t\t\t\t\tthis.instance.offset.click.top = inst.offset.click.top;\n\t\t\t\t\tthis.instance.offset.click.left = inst.offset.click.left;\n\t\t\t\t\tthis.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;\n\t\t\t\t\tthis.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;\n\n\t\t\t\t\tinst._trigger(\"toSortable\", event);\n\t\t\t\t\tinst.dropped = this.instance.element; //draggable revert needs that\n\t\t\t\t\t//hack so receive/update callbacks work (mostly)\n\t\t\t\t\tinst.currentItem = inst.element;\n\t\t\t\t\tthis.instance.fromOutside = inst;\n\n\t\t\t\t}\n\n\t\t\t\t//Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable\n\t\t\t\tif(this.instance.currentItem) this.instance._mouseDrag(event);\n\n\t\t\t} else {\n\n\t\t\t\t//If it doesn't intersect with the sortable, and it intersected before,\n\t\t\t\t//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval\n\t\t\t\tif(this.instance.isOver) {\n\n\t\t\t\t\tthis.instance.isOver = 0;\n\t\t\t\t\tthis.instance.cancelHelperRemoval = true;\n\t\t\t\t\t\n\t\t\t\t\t//Prevent reverting on this forced stop\n\t\t\t\t\tthis.instance.options.revert = false;\n\t\t\t\t\t\n\t\t\t\t\t// The out event needs to be triggered independently\n\t\t\t\t\tthis.instance._trigger('out', event, this.instance._uiHash(this.instance));\n\t\t\t\t\t\n\t\t\t\t\tthis.instance._mouseStop(event, true);\n\t\t\t\t\tthis.instance.options.helper = this.instance.options._helper;\n\n\t\t\t\t\t//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size\n\t\t\t\t\tthis.instance.currentItem.remove();\n\t\t\t\t\tif(this.instance.placeholder) this.instance.placeholder.remove();\n\n\t\t\t\t\tinst._trigger(\"fromSortable\", event);\n\t\t\t\t\tinst.dropped = false; //draggable revert needs that\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t});\n\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"cursor\", {\n\tstart: function(event, ui) {\n\t\tvar t = $('body'), o = $(this).data('draggable').options;\n\t\tif (t.css(\"cursor\")) o._cursor = t.css(\"cursor\");\n\t\tt.css(\"cursor\", o.cursor);\n\t},\n\tstop: function(event, ui) {\n\t\tvar o = $(this).data('draggable').options;\n\t\tif (o._cursor) $('body').css(\"cursor\", o._cursor);\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"iframeFix\", {\n\tstart: function(event, ui) {\n\t\tvar o = $(this).data('draggable').options;\n\t\t$(o.iframeFix === true ? \"iframe\" : o.iframeFix).each(function() {\n\t\t\t$('<div class=\"ui-draggable-iframeFix\" style=\"background: #fff;\"></div>')\n\t\t\t.css({\n\t\t\t\twidth: this.offsetWidth+\"px\", height: this.offsetHeight+\"px\",\n\t\t\t\tposition: \"absolute\", opacity: \"0.001\", zIndex: 1000\n\t\t\t})\n\t\t\t.css($(this).offset())\n\t\t\t.appendTo(\"body\");\n\t\t});\n\t},\n\tstop: function(event, ui) {\n\t\t$(\"div.ui-draggable-iframeFix\").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"opacity\", {\n\tstart: function(event, ui) {\n\t\tvar t = $(ui.helper), o = $(this).data('draggable').options;\n\t\tif(t.css(\"opacity\")) o._opacity = t.css(\"opacity\");\n\t\tt.css('opacity', o.opacity);\n\t},\n\tstop: function(event, ui) {\n\t\tvar o = $(this).data('draggable').options;\n\t\tif(o._opacity) $(ui.helper).css('opacity', o._opacity);\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"scroll\", {\n\tstart: function(event, ui) {\n\t\tvar i = $(this).data(\"draggable\");\n\t\tif(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();\n\t},\n\tdrag: function(event, ui) {\n\n\t\tvar i = $(this).data(\"draggable\"), o = i.options, scrolled = false;\n\n\t\tif(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {\n\n\t\t\tif(!o.axis || o.axis != 'x') {\n\t\t\t\tif((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)\n\t\t\t\t\ti.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;\n\t\t\t\telse if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)\n\t\t\t\t\ti.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;\n\t\t\t}\n\n\t\t\tif(!o.axis || o.axis != 'y') {\n\t\t\t\tif((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)\n\t\t\t\t\ti.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;\n\t\t\t\telse if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)\n\t\t\t\t\ti.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif(!o.axis || o.axis != 'x') {\n\t\t\t\tif(event.pageY - $(document).scrollTop() < o.scrollSensitivity)\n\t\t\t\t\tscrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);\n\t\t\t\telse if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)\n\t\t\t\t\tscrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);\n\t\t\t}\n\n\t\t\tif(!o.axis || o.axis != 'y') {\n\t\t\t\tif(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)\n\t\t\t\t\tscrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);\n\t\t\t\telse if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)\n\t\t\t\t\tscrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);\n\t\t\t}\n\n\t\t}\n\n\t\tif(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)\n\t\t\t$.ui.ddmanager.prepareOffsets(i, event);\n\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"snap\", {\n\tstart: function(event, ui) {\n\n\t\tvar i = $(this).data(\"draggable\"), o = i.options;\n\t\ti.snapElements = [];\n\n\t\t$(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {\n\t\t\tvar $t = $(this); var $o = $t.offset();\n\t\t\tif(this != i.element[0]) i.snapElements.push({\n\t\t\t\titem: this,\n\t\t\t\twidth: $t.outerWidth(), height: $t.outerHeight(),\n\t\t\t\ttop: $o.top, left: $o.left\n\t\t\t});\n\t\t});\n\n\t},\n\tdrag: function(event, ui) {\n\n\t\tvar inst = $(this).data(\"draggable\"), o = inst.options;\n\t\tvar d = o.snapTolerance;\n\n\t\tvar x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,\n\t\t\ty1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;\n\n\t\tfor (var i = inst.snapElements.length - 1; i >= 0; i--){\n\n\t\t\tvar l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,\n\t\t\t\tt = inst.snapElements[i].top, b = t + inst.snapElements[i].height;\n\n\t\t\t//Yes, I know, this is insane ;)\n\t\t\tif(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {\n\t\t\t\tif(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));\n\t\t\t\tinst.snapElements[i].snapping = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(o.snapMode != 'inner') {\n\t\t\t\tvar ts = Math.abs(t - y2) <= d;\n\t\t\t\tvar bs = Math.abs(b - y1) <= d;\n\t\t\t\tvar ls = Math.abs(l - x2) <= d;\n\t\t\t\tvar rs = Math.abs(r - x1) <= d;\n\t\t\t\tif(ts) ui.position.top = inst._convertPositionTo(\"relative\", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;\n\t\t\t\tif(bs) ui.position.top = inst._convertPositionTo(\"relative\", { top: b, left: 0 }).top - inst.margins.top;\n\t\t\t\tif(ls) ui.position.left = inst._convertPositionTo(\"relative\", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;\n\t\t\t\tif(rs) ui.position.left = inst._convertPositionTo(\"relative\", { top: 0, left: r }).left - inst.margins.left;\n\t\t\t}\n\n\t\t\tvar first = (ts || bs || ls || rs);\n\n\t\t\tif(o.snapMode != 'outer') {\n\t\t\t\tvar ts = Math.abs(t - y1) <= d;\n\t\t\t\tvar bs = Math.abs(b - y2) <= d;\n\t\t\t\tvar ls = Math.abs(l - x1) <= d;\n\t\t\t\tvar rs = Math.abs(r - x2) <= d;\n\t\t\t\tif(ts) ui.position.top = inst._convertPositionTo(\"relative\", { top: t, left: 0 }).top - inst.margins.top;\n\t\t\t\tif(bs) ui.position.top = inst._convertPositionTo(\"relative\", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;\n\t\t\t\tif(ls) ui.position.left = inst._convertPositionTo(\"relative\", { top: 0, left: l }).left - inst.margins.left;\n\t\t\t\tif(rs) ui.position.left = inst._convertPositionTo(\"relative\", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;\n\t\t\t}\n\n\t\t\tif(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))\n\t\t\t\t(inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));\n\t\t\tinst.snapElements[i].snapping = (ts || bs || ls || rs || first);\n\n\t\t};\n\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"stack\", {\n\tstart: function(event, ui) {\n\n\t\tvar o = $(this).data(\"draggable\").options;\n\n\t\tvar group = $.makeArray($(o.stack)).sort(function(a,b) {\n\t\t\treturn (parseInt($(a).css(\"zIndex\"),10) || 0) - (parseInt($(b).css(\"zIndex\"),10) || 0);\n\t\t});\n\t\tif (!group.length) { return; }\n\t\t\n\t\tvar min = parseInt(group[0].style.zIndex) || 0;\n\t\t$(group).each(function(i) {\n\t\t\tthis.style.zIndex = min + i;\n\t\t});\n\n\t\tthis[0].style.zIndex = min + group.length;\n\n\t}\n});\n\n$.ui.plugin.add(\"draggable\", \"zIndex\", {\n\tstart: function(event, ui) {\n\t\tvar t = $(ui.helper), o = $(this).data(\"draggable\").options;\n\t\tif(t.css(\"zIndex\")) o._zIndex = t.css(\"zIndex\");\n\t\tt.css('zIndex', o.zIndex);\n\t},\n\tstop: function(event, ui) {\n\t\tvar o = $(this).data(\"draggable\").options;\n\t\tif(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);\n\t}\n});\n\n})(jQuery);\n/*\n * jQuery UI Droppable 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Droppables\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.widget.js\n *\tjquery.ui.mouse.js\n *\tjquery.ui.draggable.js\n */\n(function( $, undefined ) {\n\n$.widget(\"ui.droppable\", {\n\twidgetEventPrefix: \"drop\",\n\toptions: {\n\t\taccept: '*',\n\t\tactiveClass: false,\n\t\taddClasses: true,\n\t\tgreedy: false,\n\t\thoverClass: false,\n\t\tscope: 'default',\n\t\ttolerance: 'intersect'\n\t},\n\t_create: function() {\n\n\t\tvar o = this.options, accept = o.accept;\n\t\tthis.isover = 0; this.isout = 1;\n\n\t\tthis.accept = $.isFunction(accept) ? accept : function(d) {\n\t\t\treturn d.is(accept);\n\t\t};\n\n\t\t//Store the droppable's proportions\n\t\tthis.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };\n\n\t\t// Add the reference and positions to the manager\n\t\t$.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];\n\t\t$.ui.ddmanager.droppables[o.scope].push(this);\n\n\t\t(o.addClasses && this.element.addClass(\"ui-droppable\"));\n\n\t},\n\n\tdestroy: function() {\n\t\tvar drop = $.ui.ddmanager.droppables[this.options.scope];\n\t\tfor ( var i = 0; i < drop.length; i++ )\n\t\t\tif ( drop[i] == this )\n\t\t\t\tdrop.splice(i, 1);\n\n\t\tthis.element\n\t\t\t.removeClass(\"ui-droppable ui-droppable-disabled\")\n\t\t\t.removeData(\"droppable\")\n\t\t\t.unbind(\".droppable\");\n\n\t\treturn this;\n\t},\n\n\t_setOption: function(key, value) {\n\n\t\tif(key == 'accept') {\n\t\t\tthis.accept = $.isFunction(value) ? value : function(d) {\n\t\t\t\treturn d.is(value);\n\t\t\t};\n\t\t}\n\t\t$.Widget.prototype._setOption.apply(this, arguments);\n\t},\n\n\t_activate: function(event) {\n\t\tvar draggable = $.ui.ddmanager.current;\n\t\tif(this.options.activeClass) this.element.addClass(this.options.activeClass);\n\t\t(draggable && this._trigger('activate', event, this.ui(draggable)));\n\t},\n\n\t_deactivate: function(event) {\n\t\tvar draggable = $.ui.ddmanager.current;\n\t\tif(this.options.activeClass) this.element.removeClass(this.options.activeClass);\n\t\t(draggable && this._trigger('deactivate', event, this.ui(draggable)));\n\t},\n\n\t_over: function(event) {\n\n\t\tvar draggable = $.ui.ddmanager.current;\n\t\tif (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element\n\n\t\tif (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {\n\t\t\tif(this.options.hoverClass) this.element.addClass(this.options.hoverClass);\n\t\t\tthis._trigger('over', event, this.ui(draggable));\n\t\t}\n\n\t},\n\n\t_out: function(event) {\n\n\t\tvar draggable = $.ui.ddmanager.current;\n\t\tif (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element\n\n\t\tif (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {\n\t\t\tif(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);\n\t\t\tthis._trigger('out', event, this.ui(draggable));\n\t\t}\n\n\t},\n\n\t_drop: function(event,custom) {\n\n\t\tvar draggable = custom || $.ui.ddmanager.current;\n\t\tif (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element\n\n\t\tvar childrenIntersection = false;\n\t\tthis.element.find(\":data(droppable)\").not(\".ui-draggable-dragging\").each(function() {\n\t\t\tvar inst = $.data(this, 'droppable');\n\t\t\tif(\n\t\t\t\tinst.options.greedy\n\t\t\t\t&& !inst.options.disabled\n\t\t\t\t&& inst.options.scope == draggable.options.scope\n\t\t\t\t&& inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))\n\t\t\t\t&& $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)\n\t\t\t) { childrenIntersection = true; return false; }\n\t\t});\n\t\tif(childrenIntersection) return false;\n\n\t\tif(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {\n\t\t\tif(this.options.activeClass) this.element.removeClass(this.options.activeClass);\n\t\t\tif(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);\n\t\t\tthis._trigger('drop', event, this.ui(draggable));\n\t\t\treturn this.element;\n\t\t}\n\n\t\treturn false;\n\n\t},\n\n\tui: function(c) {\n\t\treturn {\n\t\t\tdraggable: (c.currentItem || c.element),\n\t\t\thelper: c.helper,\n\t\t\tposition: c.position,\n\t\t\toffset: c.positionAbs\n\t\t};\n\t}\n\n});\n\n$.extend($.ui.droppable, {\n\tversion: \"1.8.6\"\n});\n\n$.ui.intersect = function(draggable, droppable, toleranceMode) {\n\n\tif (!droppable.offset) return false;\n\n\tvar x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,\n\t\ty1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;\n\tvar l = droppable.offset.left, r = l + droppable.proportions.width,\n\t\tt = droppable.offset.top, b = t + droppable.proportions.height;\n\n\tswitch (toleranceMode) {\n\t\tcase 'fit':\n\t\t\treturn (l <= x1 && x2 <= r\n\t\t\t\t&& t <= y1 && y2 <= b);\n\t\t\tbreak;\n\t\tcase 'intersect':\n\t\t\treturn (l < x1 + (draggable.helperProportions.width / 2) // Right Half\n\t\t\t\t&& x2 - (draggable.helperProportions.width / 2) < r // Left Half\n\t\t\t\t&& t < y1 + (draggable.helperProportions.height / 2) // Bottom Half\n\t\t\t\t&& y2 - (draggable.helperProportions.height / 2) < b ); // Top Half\n\t\t\tbreak;\n\t\tcase 'pointer':\n\t\t\tvar draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),\n\t\t\t\tdraggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),\n\t\t\t\tisOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);\n\t\t\treturn isOver;\n\t\t\tbreak;\n\t\tcase 'touch':\n\t\t\treturn (\n\t\t\t\t\t(y1 >= t && y1 <= b) ||\t// Top edge touching\n\t\t\t\t\t(y2 >= t && y2 <= b) ||\t// Bottom edge touching\n\t\t\t\t\t(y1 < t && y2 > b)\t\t// Surrounded vertically\n\t\t\t\t) && (\n\t\t\t\t\t(x1 >= l && x1 <= r) ||\t// Left edge touching\n\t\t\t\t\t(x2 >= l && x2 <= r) ||\t// Right edge touching\n\t\t\t\t\t(x1 < l && x2 > r)\t\t// Surrounded horizontally\n\t\t\t\t);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn false;\n\t\t\tbreak;\n\t\t}\n\n};\n\n/*\n\tThis manager tracks offsets of draggables and droppables\n*/\n$.ui.ddmanager = {\n\tcurrent: null,\n\tdroppables: { 'default': [] },\n\tprepareOffsets: function(t, event) {\n\n\t\tvar m = $.ui.ddmanager.droppables[t.options.scope] || [];\n\t\tvar type = event ? event.type : null; // workaround for #2317\n\t\tvar list = (t.currentItem || t.element).find(\":data(droppable)\").andSelf();\n\n\t\tdroppablesLoop: for (var i = 0; i < m.length; i++) {\n\n\t\t\tif(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue;\t//No disabled and non-accepted\n\t\t\tfor (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item\n\t\t\tm[i].visible = m[i].element.css(\"display\") != \"none\"; if(!m[i].visible) continue; \t\t\t\t\t\t\t\t\t//If the element is not visible, continue\n\n\t\t\tm[i].offset = m[i].element.offset();\n\t\t\tm[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };\n\n\t\t\tif(type == \"mousedown\") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables\n\n\t\t}\n\n\t},\n\tdrop: function(draggable, event) {\n\n\t\tvar dropped = false;\n\t\t$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {\n\n\t\t\tif(!this.options) return;\n\t\t\tif (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))\n\t\t\t\tdropped = dropped || this._drop.call(this, event);\n\n\t\t\tif (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {\n\t\t\t\tthis.isout = 1; this.isover = 0;\n\t\t\t\tthis._deactivate.call(this, event);\n\t\t\t}\n\n\t\t});\n\t\treturn dropped;\n\n\t},\n\tdrag: function(draggable, event) {\n\n\t\t//If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.\n\t\tif(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);\n\n\t\t//Run through all droppables and check their positions based on specific tolerance options\n\t\t$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {\n\n\t\t\tif(this.options.disabled || this.greedyChild || !this.visible) return;\n\t\t\tvar intersects = $.ui.intersect(draggable, this, this.options.tolerance);\n\n\t\t\tvar c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);\n\t\t\tif(!c) return;\n\n\t\t\tvar parentInstance;\n\t\t\tif (this.options.greedy) {\n\t\t\t\tvar parent = this.element.parents(':data(droppable):eq(0)');\n\t\t\t\tif (parent.length) {\n\t\t\t\t\tparentInstance = $.data(parent[0], 'droppable');\n\t\t\t\t\tparentInstance.greedyChild = (c == 'isover' ? 1 : 0);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// we just moved into a greedy child\n\t\t\tif (parentInstance && c == 'isover') {\n\t\t\t\tparentInstance['isover'] = 0;\n\t\t\t\tparentInstance['isout'] = 1;\n\t\t\t\tparentInstance._out.call(parentInstance, event);\n\t\t\t}\n\n\t\t\tthis[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;\n\t\t\tthis[c == \"isover\" ? \"_over\" : \"_out\"].call(this, event);\n\n\t\t\t// we just moved out of a greedy child\n\t\t\tif (parentInstance && c == 'isout') {\n\t\t\t\tparentInstance['isout'] = 0;\n\t\t\t\tparentInstance['isover'] = 1;\n\t\t\t\tparentInstance._over.call(parentInstance, event);\n\t\t\t}\n\t\t});\n\n\t}\n};\n\n})(jQuery);\n/*\n * jQuery UI Resizable 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Resizables\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.mouse.js\n *\tjquery.ui.widget.js\n */\n(function( $, undefined ) {\n\n$.widget(\"ui.resizable\", $.ui.mouse, {\n\twidgetEventPrefix: \"resize\",\n\toptions: {\n\t\talsoResize: false,\n\t\tanimate: false,\n\t\tanimateDuration: \"slow\",\n\t\tanimateEasing: \"swing\",\n\t\taspectRatio: false,\n\t\tautoHide: false,\n\t\tcontainment: false,\n\t\tghost: false,\n\t\tgrid: false,\n\t\thandles: \"e,s,se\",\n\t\thelper: false,\n\t\tmaxHeight: null,\n\t\tmaxWidth: null,\n\t\tminHeight: 10,\n\t\tminWidth: 10,\n\t\tzIndex: 1000\n\t},\n\t_create: function() {\n\n\t\tvar self = this, o = this.options;\n\t\tthis.element.addClass(\"ui-resizable\");\n\n\t\t$.extend(this, {\n\t\t\t_aspectRatio: !!(o.aspectRatio),\n\t\t\taspectRatio: o.aspectRatio,\n\t\t\toriginalElement: this.element,\n\t\t\t_proportionallyResizeElements: [],\n\t\t\t_helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null\n\t\t});\n\n\t\t//Wrap the element if it cannot hold child nodes\n\t\tif(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {\n\n\t\t\t//Opera fix for relative positioning\n\t\t\tif (/relative/.test(this.element.css('position')) && $.browser.opera)\n\t\t\t\tthis.element.css({ position: 'relative', top: 'auto', left: 'auto' });\n\n\t\t\t//Create a wrapper element and set the wrapper to the new current internal element\n\t\t\tthis.element.wrap(\n\t\t\t\t$('<div class=\"ui-wrapper\" style=\"overflow: hidden;\"></div>').css({\n\t\t\t\t\tposition: this.element.css('position'),\n\t\t\t\t\twidth: this.element.outerWidth(),\n\t\t\t\t\theight: this.element.outerHeight(),\n\t\t\t\t\ttop: this.element.css('top'),\n\t\t\t\t\tleft: this.element.css('left')\n\t\t\t\t})\n\t\t\t);\n\n\t\t\t//Overwrite the original this.element\n\t\t\tthis.element = this.element.parent().data(\n\t\t\t\t\"resizable\", this.element.data('resizable')\n\t\t\t);\n\n\t\t\tthis.elementIsWrapper = true;\n\n\t\t\t//Move margins to the wrapper\n\t\t\tthis.element.css({ marginLeft: this.originalElement.css(\"marginLeft\"), marginTop: this.originalElement.css(\"marginTop\"), marginRight: this.originalElement.css(\"marginRight\"), marginBottom: this.originalElement.css(\"marginBottom\") });\n\t\t\tthis.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});\n\n\t\t\t//Prevent Safari textarea resize\n\t\t\tthis.originalResizeStyle = this.originalElement.css('resize');\n\t\t\tthis.originalElement.css('resize', 'none');\n\n\t\t\t//Push the actual element to our proportionallyResize internal array\n\t\t\tthis._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));\n\n\t\t\t// avoid IE jump (hard set the margin)\n\t\t\tthis.originalElement.css({ margin: this.originalElement.css('margin') });\n\n\t\t\t// fix handlers offset\n\t\t\tthis._proportionallyResize();\n\n\t\t}\n\n\t\tthis.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? \"e,s,se\" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' });\n\t\tif(this.handles.constructor == String) {\n\n\t\t\tif(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';\n\t\t\tvar n = this.handles.split(\",\"); this.handles = {};\n\n\t\t\tfor(var i = 0; i < n.length; i++) {\n\n\t\t\t\tvar handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;\n\t\t\t\tvar axis = $('<div class=\"ui-resizable-handle ' + hname + '\"></div>');\n\n\t\t\t\t// increase zIndex of sw, se, ne, nw axis\n\t\t\t\t//TODO : this modifies original option\n\t\t\t\tif(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex });\n\n\t\t\t\t//TODO : What's going on here?\n\t\t\t\tif ('se' == handle) {\n\t\t\t\t\taxis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');\n\t\t\t\t};\n\n\t\t\t\t//Insert into internal handles object and append to element\n\t\t\t\tthis.handles[handle] = '.ui-resizable-'+handle;\n\t\t\t\tthis.element.append(axis);\n\t\t\t}\n\n\t\t}\n\n\t\tthis._renderAxis = function(target) {\n\n\t\t\ttarget = target || this.element;\n\n\t\t\tfor(var i in this.handles) {\n\n\t\t\t\tif(this.handles[i].constructor == String)\n\t\t\t\t\tthis.handles[i] = $(this.handles[i], this.element).show();\n\n\t\t\t\t//Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)\n\t\t\t\tif (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {\n\n\t\t\t\t\tvar axis = $(this.handles[i], this.element), padWrapper = 0;\n\n\t\t\t\t\t//Checking the correct pad and border\n\t\t\t\t\tpadWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();\n\n\t\t\t\t\t//The padding type i have to apply...\n\t\t\t\t\tvar padPos = [ 'padding',\n\t\t\t\t\t\t/ne|nw|n/.test(i) ? 'Top' :\n\t\t\t\t\t\t/se|sw|s/.test(i) ? 'Bottom' :\n\t\t\t\t\t\t/^e$/.test(i) ? 'Right' : 'Left' ].join(\"\");\n\n\t\t\t\t\ttarget.css(padPos, padWrapper);\n\n\t\t\t\t\tthis._proportionallyResize();\n\n\t\t\t\t}\n\n\t\t\t\t//TODO: What's that good for? There's not anything to be executed left\n\t\t\t\tif(!$(this.handles[i]).length)\n\t\t\t\t\tcontinue;\n\n\t\t\t}\n\t\t};\n\n\t\t//TODO: make renderAxis a prototype function\n\t\tthis._renderAxis(this.element);\n\n\t\tthis._handles = $('.ui-resizable-handle', this.element)\n\t\t\t.disableSelection();\n\n\t\t//Matching axis name\n\t\tthis._handles.mouseover(function() {\n\t\t\tif (!self.resizing) {\n\t\t\t\tif (this.className)\n\t\t\t\t\tvar axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);\n\t\t\t\t//Axis, default = se\n\t\t\t\tself.axis = axis && axis[1] ? axis[1] : 'se';\n\t\t\t}\n\t\t});\n\n\t\t//If we want to auto hide the elements\n\t\tif (o.autoHide) {\n\t\t\tthis._handles.hide();\n\t\t\t$(this.element)\n\t\t\t\t.addClass(\"ui-resizable-autohide\")\n\t\t\t\t.hover(function() {\n\t\t\t\t\t$(this).removeClass(\"ui-resizable-autohide\");\n\t\t\t\t\tself._handles.show();\n\t\t\t\t},\n\t\t\t\tfunction(){\n\t\t\t\t\tif (!self.resizing) {\n\t\t\t\t\t\t$(this).addClass(\"ui-resizable-autohide\");\n\t\t\t\t\t\tself._handles.hide();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}\n\n\t\t//Initialize the mouse interaction\n\t\tthis._mouseInit();\n\n\t},\n\n\tdestroy: function() {\n\n\t\tthis._mouseDestroy();\n\n\t\tvar _destroy = function(exp) {\n\t\t\t$(exp).removeClass(\"ui-resizable ui-resizable-disabled ui-resizable-resizing\")\n\t\t\t\t.removeData(\"resizable\").unbind(\".resizable\").find('.ui-resizable-handle').remove();\n\t\t};\n\n\t\t//TODO: Unwrap at same DOM position\n\t\tif (this.elementIsWrapper) {\n\t\t\t_destroy(this.element);\n\t\t\tvar wrapper = this.element;\n\t\t\twrapper.after(\n\t\t\t\tthis.originalElement.css({\n\t\t\t\t\tposition: wrapper.css('position'),\n\t\t\t\t\twidth: wrapper.outerWidth(),\n\t\t\t\t\theight: wrapper.outerHeight(),\n\t\t\t\t\ttop: wrapper.css('top'),\n\t\t\t\t\tleft: wrapper.css('left')\n\t\t\t\t})\n\t\t\t).remove();\n\t\t}\n\n\t\tthis.originalElement.css('resize', this.originalResizeStyle);\n\t\t_destroy(this.originalElement);\n\n\t\treturn this;\n\t},\n\n\t_mouseCapture: function(event) {\n\t\tvar handle = false;\n\t\tfor (var i in this.handles) {\n\t\t\tif ($(this.handles[i])[0] == event.target) {\n\t\t\t\thandle = true;\n\t\t\t}\n\t\t}\n\n\t\treturn !this.options.disabled && handle;\n\t},\n\n\t_mouseStart: function(event) {\n\n\t\tvar o = this.options, iniPos = this.element.position(), el = this.element;\n\n\t\tthis.resizing = true;\n\t\tthis.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };\n\n\t\t// bugfix for http://dev.jquery.com/ticket/1749\n\t\tif (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {\n\t\t\tel.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });\n\t\t}\n\n\t\t//Opera fixing relative position\n\t\tif ($.browser.opera && (/relative/).test(el.css('position')))\n\t\t\tel.css({ position: 'relative', top: 'auto', left: 'auto' });\n\n\t\tthis._renderProxy();\n\n\t\tvar curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));\n\n\t\tif (o.containment) {\n\t\t\tcurleft += $(o.containment).scrollLeft() || 0;\n\t\t\tcurtop += $(o.containment).scrollTop() || 0;\n\t\t}\n\n\t\t//Store needed variables\n\t\tthis.offset = this.helper.offset();\n\t\tthis.position = { left: curleft, top: curtop };\n\t\tthis.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };\n\t\tthis.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };\n\t\tthis.originalPosition = { left: curleft, top: curtop };\n\t\tthis.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };\n\t\tthis.originalMousePosition = { left: event.pageX, top: event.pageY };\n\n\t\t//Aspect Ratio\n\t\tthis.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);\n\n\t    var cursor = $('.ui-resizable-' + this.axis).css('cursor');\n\t    $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);\n\n\t\tel.addClass(\"ui-resizable-resizing\");\n\t\tthis._propagate(\"start\", event);\n\t\treturn true;\n\t},\n\n\t_mouseDrag: function(event) {\n\n\t\t//Increase performance, avoid regex\n\t\tvar el = this.helper, o = this.options, props = {},\n\t\t\tself = this, smp = this.originalMousePosition, a = this.axis;\n\n\t\tvar dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;\n\t\tvar trigger = this._change[a];\n\t\tif (!trigger) return false;\n\n\t\t// Calculate the attrs that will be change\n\t\tvar data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;\n\n\t\tif (this._aspectRatio || event.shiftKey)\n\t\t\tdata = this._updateRatio(data, event);\n\n\t\tdata = this._respectSize(data, event);\n\n\t\t// plugins callbacks need to be called first\n\t\tthis._propagate(\"resize\", event);\n\n\t\tel.css({\n\t\t\ttop: this.position.top + \"px\", left: this.position.left + \"px\",\n\t\t\twidth: this.size.width + \"px\", height: this.size.height + \"px\"\n\t\t});\n\n\t\tif (!this._helper && this._proportionallyResizeElements.length)\n\t\t\tthis._proportionallyResize();\n\n\t\tthis._updateCache(data);\n\n\t\t// calling the user callback at the end\n\t\tthis._trigger('resize', event, this.ui());\n\n\t\treturn false;\n\t},\n\n\t_mouseStop: function(event) {\n\n\t\tthis.resizing = false;\n\t\tvar o = this.options, self = this;\n\n\t\tif(this._helper) {\n\t\t\tvar pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),\n\t\t\t\t\t\tsoffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,\n\t\t\t\t\t\t\tsoffsetw = ista ? 0 : self.sizeDiff.width;\n\n\t\t\tvar s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },\n\t\t\t\tleft = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,\n\t\t\t\ttop = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;\n\n\t\t\tif (!o.animate)\n\t\t\t\tthis.element.css($.extend(s, { top: top, left: left }));\n\n\t\t\tself.helper.height(self.size.height);\n\t\t\tself.helper.width(self.size.width);\n\n\t\t\tif (this._helper && !o.animate) this._proportionallyResize();\n\t\t}\n\n\t\t$('body').css('cursor', 'auto');\n\n\t\tthis.element.removeClass(\"ui-resizable-resizing\");\n\n\t\tthis._propagate(\"stop\", event);\n\n\t\tif (this._helper) this.helper.remove();\n\t\treturn false;\n\n\t},\n\n\t_updateCache: function(data) {\n\t\tvar o = this.options;\n\t\tthis.offset = this.helper.offset();\n\t\tif (isNumber(data.left)) this.position.left = data.left;\n\t\tif (isNumber(data.top)) this.position.top = data.top;\n\t\tif (isNumber(data.height)) this.size.height = data.height;\n\t\tif (isNumber(data.width)) this.size.width = data.width;\n\t},\n\n\t_updateRatio: function(data, event) {\n\n\t\tvar o = this.options, cpos = this.position, csize = this.size, a = this.axis;\n\n\t\tif (data.height) data.width = (csize.height * this.aspectRatio);\n\t\telse if (data.width) data.height = (csize.width / this.aspectRatio);\n\n\t\tif (a == 'sw') {\n\t\t\tdata.left = cpos.left + (csize.width - data.width);\n\t\t\tdata.top = null;\n\t\t}\n\t\tif (a == 'nw') {\n\t\t\tdata.top = cpos.top + (csize.height - data.height);\n\t\t\tdata.left = cpos.left + (csize.width - data.width);\n\t\t}\n\n\t\treturn data;\n\t},\n\n\t_respectSize: function(data, event) {\n\n\t\tvar el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,\n\t\t\t\tismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),\n\t\t\t\t\tisminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);\n\n\t\tif (isminw) data.width = o.minWidth;\n\t\tif (isminh) data.height = o.minHeight;\n\t\tif (ismaxw) data.width = o.maxWidth;\n\t\tif (ismaxh) data.height = o.maxHeight;\n\n\t\tvar dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;\n\t\tvar cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);\n\n\t\tif (isminw && cw) data.left = dw - o.minWidth;\n\t\tif (ismaxw && cw) data.left = dw - o.maxWidth;\n\t\tif (isminh && ch)\tdata.top = dh - o.minHeight;\n\t\tif (ismaxh && ch)\tdata.top = dh - o.maxHeight;\n\n\t\t// fixing jump error on top/left - bug #2330\n\t\tvar isNotwh = !data.width && !data.height;\n\t\tif (isNotwh && !data.left && data.top) data.top = null;\n\t\telse if (isNotwh && !data.top && data.left) data.left = null;\n\n\t\treturn data;\n\t},\n\n\t_proportionallyResize: function() {\n\n\t\tvar o = this.options;\n\t\tif (!this._proportionallyResizeElements.length) return;\n\t\tvar element = this.helper || this.element;\n\n\t\tfor (var i=0; i < this._proportionallyResizeElements.length; i++) {\n\n\t\t\tvar prel = this._proportionallyResizeElements[i];\n\n\t\t\tif (!this.borderDif) {\n\t\t\t\tvar b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],\n\t\t\t\t\tp = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];\n\n\t\t\t\tthis.borderDif = $.map(b, function(v, i) {\n\t\t\t\t\tvar border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;\n\t\t\t\t\treturn border + padding;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length)))\n\t\t\t\tcontinue;\n\n\t\t\tprel.css({\n\t\t\t\theight: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,\n\t\t\t\twidth: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0\n\t\t\t});\n\n\t\t};\n\n\t},\n\n\t_renderProxy: function() {\n\n\t\tvar el = this.element, o = this.options;\n\t\tthis.elementOffset = el.offset();\n\n\t\tif(this._helper) {\n\n\t\t\tthis.helper = this.helper || $('<div style=\"overflow:hidden;\"></div>');\n\n\t\t\t// fix ie6 offset TODO: This seems broken\n\t\t\tvar ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),\n\t\t\tpxyoffset = ( ie6 ? 2 : -1 );\n\n\t\t\tthis.helper.addClass(this._helper).css({\n\t\t\t\twidth: this.element.outerWidth() + pxyoffset,\n\t\t\t\theight: this.element.outerHeight() + pxyoffset,\n\t\t\t\tposition: 'absolute',\n\t\t\t\tleft: this.elementOffset.left - ie6offset +'px',\n\t\t\t\ttop: this.elementOffset.top - ie6offset +'px',\n\t\t\t\tzIndex: ++o.zIndex //TODO: Don't modify option\n\t\t\t});\n\n\t\t\tthis.helper\n\t\t\t\t.appendTo(\"body\")\n\t\t\t\t.disableSelection();\n\n\t\t} else {\n\t\t\tthis.helper = this.element;\n\t\t}\n\n\t},\n\n\t_change: {\n\t\te: function(event, dx, dy) {\n\t\t\treturn { width: this.originalSize.width + dx };\n\t\t},\n\t\tw: function(event, dx, dy) {\n\t\t\tvar o = this.options, cs = this.originalSize, sp = this.originalPosition;\n\t\t\treturn { left: sp.left + dx, width: cs.width - dx };\n\t\t},\n\t\tn: function(event, dx, dy) {\n\t\t\tvar o = this.options, cs = this.originalSize, sp = this.originalPosition;\n\t\t\treturn { top: sp.top + dy, height: cs.height - dy };\n\t\t},\n\t\ts: function(event, dx, dy) {\n\t\t\treturn { height: this.originalSize.height + dy };\n\t\t},\n\t\tse: function(event, dx, dy) {\n\t\t\treturn $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));\n\t\t},\n\t\tsw: function(event, dx, dy) {\n\t\t\treturn $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));\n\t\t},\n\t\tne: function(event, dx, dy) {\n\t\t\treturn $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));\n\t\t},\n\t\tnw: function(event, dx, dy) {\n\t\t\treturn $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));\n\t\t}\n\t},\n\n\t_propagate: function(n, event) {\n\t\t$.ui.plugin.call(this, n, [event, this.ui()]);\n\t\t(n != \"resize\" && this._trigger(n, event, this.ui()));\n\t},\n\n\tplugins: {},\n\n\tui: function() {\n\t\treturn {\n\t\t\toriginalElement: this.originalElement,\n\t\t\telement: this.element,\n\t\t\thelper: this.helper,\n\t\t\tposition: this.position,\n\t\t\tsize: this.size,\n\t\t\toriginalSize: this.originalSize,\n\t\t\toriginalPosition: this.originalPosition\n\t\t};\n\t}\n\n});\n\n$.extend($.ui.resizable, {\n\tversion: \"1.8.6\"\n});\n\n/*\n * Resizable Extensions\n */\n\n$.ui.plugin.add(\"resizable\", \"alsoResize\", {\n\n\tstart: function (event, ui) {\n\t\tvar self = $(this).data(\"resizable\"), o = self.options;\n\n\t\tvar _store = function (exp) {\n\t\t\t$(exp).each(function() {\n\t\t\t\tvar el = $(this);\n\t\t\t\tel.data(\"resizable-alsoresize\", {\n\t\t\t\t\twidth: parseInt(el.width(), 10), height: parseInt(el.height(), 10),\n\t\t\t\t\tleft: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10),\n\t\t\t\t\tposition: el.css('position') // to reset Opera on stop()\n\t\t\t\t});\n\t\t\t});\n\t\t};\n\n\t\tif (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {\n\t\t\tif (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }\n\t\t\telse { $.each(o.alsoResize, function (exp) { _store(exp); }); }\n\t\t}else{\n\t\t\t_store(o.alsoResize);\n\t\t}\n\t},\n\n\tresize: function (event, ui) {\n\t\tvar self = $(this).data(\"resizable\"), o = self.options, os = self.originalSize, op = self.originalPosition;\n\n\t\tvar delta = {\n\t\t\theight: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0,\n\t\t\ttop: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0\n\t\t},\n\n\t\t_alsoResize = function (exp, c) {\n\t\t\t$(exp).each(function() {\n\t\t\t\tvar el = $(this), start = $(this).data(\"resizable-alsoresize\"), style = {}, \n\t\t\t\t\tcss = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left'];\n\n\t\t\t\t$.each(css, function (i, prop) {\n\t\t\t\t\tvar sum = (start[prop]||0) + (delta[prop]||0);\n\t\t\t\t\tif (sum && sum >= 0)\n\t\t\t\t\t\tstyle[prop] = sum || null;\n\t\t\t\t});\n\n\t\t\t\t// Opera fixing relative position\n\t\t\t\tif ($.browser.opera && /relative/.test(el.css('position'))) {\n\t\t\t\t\tself._revertToRelativePosition = true;\n\t\t\t\t\tel.css({ position: 'absolute', top: 'auto', left: 'auto' });\n\t\t\t\t}\n\n\t\t\t\tel.css(style);\n\t\t\t});\n\t\t};\n\n\t\tif (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {\n\t\t\t$.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });\n\t\t}else{\n\t\t\t_alsoResize(o.alsoResize);\n\t\t}\n\t},\n\n\tstop: function (event, ui) {\n\t\tvar self = $(this).data(\"resizable\"), o = self.options;\n\n\t\tvar _reset = function (exp) {\n\t\t\t$(exp).each(function() {\n\t\t\t\tvar el = $(this);\n\t\t\t\t// reset position for Opera - no need to verify it was changed\n\t\t\t\tel.css({ position: el.data(\"resizable-alsoresize\").position });\n\t\t\t});\n\t\t};\n\n\t\tif (self._revertToRelativePosition) {\n\t\t\tself._revertToRelativePosition = false;\n\t\t\tif (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {\n\t\t\t\t$.each(o.alsoResize, function (exp) { _reset(exp); });\n\t\t\t}else{\n\t\t\t\t_reset(o.alsoResize);\n\t\t\t}\n\t\t}\n\n\t\t$(this).removeData(\"resizable-alsoresize\");\n\t}\n});\n\n$.ui.plugin.add(\"resizable\", \"animate\", {\n\n\tstop: function(event, ui) {\n\t\tvar self = $(this).data(\"resizable\"), o = self.options;\n\n\t\tvar pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),\n\t\t\t\t\tsoffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,\n\t\t\t\t\t\tsoffsetw = ista ? 0 : self.sizeDiff.width;\n\n\t\tvar style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },\n\t\t\t\t\tleft = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,\n\t\t\t\t\t\ttop = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;\n\n\t\tself.element.animate(\n\t\t\t$.extend(style, top && left ? { top: top, left: left } : {}), {\n\t\t\t\tduration: o.animateDuration,\n\t\t\t\teasing: o.animateEasing,\n\t\t\t\tstep: function() {\n\n\t\t\t\t\tvar data = {\n\t\t\t\t\t\twidth: parseInt(self.element.css('width'), 10),\n\t\t\t\t\t\theight: parseInt(self.element.css('height'), 10),\n\t\t\t\t\t\ttop: parseInt(self.element.css('top'), 10),\n\t\t\t\t\t\tleft: parseInt(self.element.css('left'), 10)\n\t\t\t\t\t};\n\n\t\t\t\t\tif (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });\n\n\t\t\t\t\t// propagating resize, and updating values for each animation step\n\t\t\t\t\tself._updateCache(data);\n\t\t\t\t\tself._propagate(\"resize\", event);\n\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n});\n\n$.ui.plugin.add(\"resizable\", \"containment\", {\n\n\tstart: function(event, ui) {\n\t\tvar self = $(this).data(\"resizable\"), o = self.options, el = self.element;\n\t\tvar oc = o.containment,\tce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;\n\t\tif (!ce) return;\n\n\t\tself.containerElement = $(ce);\n\n\t\tif (/document/.test(oc) || oc == document) {\n\t\t\tself.containerOffset = { left: 0, top: 0 };\n\t\t\tself.containerPosition = { left: 0, top: 0 };\n\n\t\t\tself.parentData = {\n\t\t\t\telement: $(document), left: 0, top: 0,\n\t\t\t\twidth: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight\n\t\t\t};\n\t\t}\n\n\t\t// i'm a node, so compute top, left, right, bottom\n\t\telse {\n\t\t\tvar element = $(ce), p = [];\n\t\t\t$([ \"Top\", \"Right\", \"Left\", \"Bottom\" ]).each(function(i, name) { p[i] = num(element.css(\"padding\" + name)); });\n\n\t\t\tself.containerOffset = element.offset();\n\t\t\tself.containerPosition = element.position();\n\t\t\tself.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };\n\n\t\t\tvar co = self.containerOffset, ch = self.containerSize.height,\tcw = self.containerSize.width,\n\t\t\t\t\t\twidth = ($.ui.hasScroll(ce, \"left\") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);\n\n\t\t\tself.parentData = {\n\t\t\t\telement: ce, left: co.left, top: co.top, width: width, height: height\n\t\t\t};\n\t\t}\n\t},\n\n\tresize: function(event, ui) {\n\t\tvar self = $(this).data(\"resizable\"), o = self.options,\n\t\t\t\tps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position,\n\t\t\t\tpRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement;\n\n\t\tif (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;\n\n\t\tif (cp.left < (self._helper ? co.left : 0)) {\n\t\t\tself.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left));\n\t\t\tif (pRatio) self.size.height = self.size.width / o.aspectRatio;\n\t\t\tself.position.left = o.helper ? co.left : 0;\n\t\t}\n\n\t\tif (cp.top < (self._helper ? co.top : 0)) {\n\t\t\tself.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top);\n\t\t\tif (pRatio) self.size.width = self.size.height * o.aspectRatio;\n\t\t\tself.position.top = self._helper ? co.top : 0;\n\t\t}\n\n\t\tself.offset.left = self.parentData.left+self.position.left;\n\t\tself.offset.top = self.parentData.top+self.position.top;\n\n\t\tvar woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ),\n\t\t\t\t\thoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height );\n\n\t\tvar isParent = self.containerElement.get(0) == self.element.parent().get(0),\n\t\t    isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position'));\n\n\t\tif(isParent && isOffsetRelative) woset -= self.parentData.left;\n\n\t\tif (woset + self.size.width >= self.parentData.width) {\n\t\t\tself.size.width = self.parentData.width - woset;\n\t\t\tif (pRatio) self.size.height = self.size.width / self.aspectRatio;\n\t\t}\n\n\t\tif (hoset + self.size.height >= self.parentData.height) {\n\t\t\tself.size.height = self.parentData.height - hoset;\n\t\t\tif (pRatio) self.size.width = self.size.height * self.aspectRatio;\n\t\t}\n\t},\n\n\tstop: function(event, ui){\n\t\tvar self = $(this).data(\"resizable\"), o = self.options, cp = self.position,\n\t\t\t\tco = self.containerOffset, cop = self.containerPosition, ce = self.containerElement;\n\n\t\tvar helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height;\n\n\t\tif (self._helper && !o.animate && (/relative/).test(ce.css('position')))\n\t\t\t$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });\n\n\t\tif (self._helper && !o.animate && (/static/).test(ce.css('position')))\n\t\t\t$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });\n\n\t}\n});\n\n$.ui.plugin.add(\"resizable\", \"ghost\", {\n\n\tstart: function(event, ui) {\n\n\t\tvar self = $(this).data(\"resizable\"), o = self.options, cs = self.size;\n\n\t\tself.ghost = self.originalElement.clone();\n\t\tself.ghost\n\t\t\t.css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })\n\t\t\t.addClass('ui-resizable-ghost')\n\t\t\t.addClass(typeof o.ghost == 'string' ? o.ghost : '');\n\n\t\tself.ghost.appendTo(self.helper);\n\n\t},\n\n\tresize: function(event, ui){\n\t\tvar self = $(this).data(\"resizable\"), o = self.options;\n\t\tif (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });\n\t},\n\n\tstop: function(event, ui){\n\t\tvar self = $(this).data(\"resizable\"), o = self.options;\n\t\tif (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));\n\t}\n\n});\n\n$.ui.plugin.add(\"resizable\", \"grid\", {\n\n\tresize: function(event, ui) {\n\t\tvar self = $(this).data(\"resizable\"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey;\n\t\to.grid = typeof o.grid == \"number\" ? [o.grid, o.grid] : o.grid;\n\t\tvar ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);\n\n\t\tif (/^(se|s|e)$/.test(a)) {\n\t\t\tself.size.width = os.width + ox;\n\t\t\tself.size.height = os.height + oy;\n\t\t}\n\t\telse if (/^(ne)$/.test(a)) {\n\t\t\tself.size.width = os.width + ox;\n\t\t\tself.size.height = os.height + oy;\n\t\t\tself.position.top = op.top - oy;\n\t\t}\n\t\telse if (/^(sw)$/.test(a)) {\n\t\t\tself.size.width = os.width + ox;\n\t\t\tself.size.height = os.height + oy;\n\t\t\tself.position.left = op.left - ox;\n\t\t}\n\t\telse {\n\t\t\tself.size.width = os.width + ox;\n\t\t\tself.size.height = os.height + oy;\n\t\t\tself.position.top = op.top - oy;\n\t\t\tself.position.left = op.left - ox;\n\t\t}\n\t}\n\n});\n\nvar num = function(v) {\n\treturn parseInt(v, 10) || 0;\n};\n\nvar isNumber = function(value) {\n\treturn !isNaN(parseInt(value, 10));\n};\n\n})(jQuery);\n/*\n * jQuery UI Selectable 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Selectables\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.mouse.js\n *\tjquery.ui.widget.js\n */\n(function( $, undefined ) {\n\n$.widget(\"ui.selectable\", $.ui.mouse, {\n\toptions: {\n\t\tappendTo: 'body',\n\t\tautoRefresh: true,\n\t\tdistance: 0,\n\t\tfilter: '*',\n\t\ttolerance: 'touch'\n\t},\n\t_create: function() {\n\t\tvar self = this;\n\n\t\tthis.element.addClass(\"ui-selectable\");\n\n\t\tthis.dragged = false;\n\n\t\t// cache selectee children based on filter\n\t\tvar selectees;\n\t\tthis.refresh = function() {\n\t\t\tselectees = $(self.options.filter, self.element[0]);\n\t\t\tselectees.each(function() {\n\t\t\t\tvar $this = $(this);\n\t\t\t\tvar pos = $this.offset();\n\t\t\t\t$.data(this, \"selectable-item\", {\n\t\t\t\t\telement: this,\n\t\t\t\t\t$element: $this,\n\t\t\t\t\tleft: pos.left,\n\t\t\t\t\ttop: pos.top,\n\t\t\t\t\tright: pos.left + $this.outerWidth(),\n\t\t\t\t\tbottom: pos.top + $this.outerHeight(),\n\t\t\t\t\tstartselected: false,\n\t\t\t\t\tselected: $this.hasClass('ui-selected'),\n\t\t\t\t\tselecting: $this.hasClass('ui-selecting'),\n\t\t\t\t\tunselecting: $this.hasClass('ui-unselecting')\n\t\t\t\t});\n\t\t\t});\n\t\t};\n\t\tthis.refresh();\n\n\t\tthis.selectees = selectees.addClass(\"ui-selectee\");\n\n\t\tthis._mouseInit();\n\n\t\tthis.helper = $(\"<div class='ui-selectable-helper'></div>\");\n\t},\n\n\tdestroy: function() {\n\t\tthis.selectees\n\t\t\t.removeClass(\"ui-selectee\")\n\t\t\t.removeData(\"selectable-item\");\n\t\tthis.element\n\t\t\t.removeClass(\"ui-selectable ui-selectable-disabled\")\n\t\t\t.removeData(\"selectable\")\n\t\t\t.unbind(\".selectable\");\n\t\tthis._mouseDestroy();\n\n\t\treturn this;\n\t},\n\n\t_mouseStart: function(event) {\n\t\tvar self = this;\n\n\t\tthis.opos = [event.pageX, event.pageY];\n\n\t\tif (this.options.disabled)\n\t\t\treturn;\n\n\t\tvar options = this.options;\n\n\t\tthis.selectees = $(options.filter, this.element[0]);\n\n\t\tthis._trigger(\"start\", event);\n\n\t\t$(options.appendTo).append(this.helper);\n\t\t// position helper (lasso)\n\t\tthis.helper.css({\n\t\t\t\"left\": event.clientX,\n\t\t\t\"top\": event.clientY,\n\t\t\t\"width\": 0,\n\t\t\t\"height\": 0\n\t\t});\n\n\t\tif (options.autoRefresh) {\n\t\t\tthis.refresh();\n\t\t}\n\n\t\tthis.selectees.filter('.ui-selected').each(function() {\n\t\t\tvar selectee = $.data(this, \"selectable-item\");\n\t\t\tselectee.startselected = true;\n\t\t\tif (!event.metaKey) {\n\t\t\t\tselectee.$element.removeClass('ui-selected');\n\t\t\t\tselectee.selected = false;\n\t\t\t\tselectee.$element.addClass('ui-unselecting');\n\t\t\t\tselectee.unselecting = true;\n\t\t\t\t// selectable UNSELECTING callback\n\t\t\t\tself._trigger(\"unselecting\", event, {\n\t\t\t\t\tunselecting: selectee.element\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\t$(event.target).parents().andSelf().each(function() {\n\t\t\tvar selectee = $.data(this, \"selectable-item\");\n\t\t\tif (selectee) {\n\t\t\t\tvar doSelect = !event.metaKey || !selectee.$element.hasClass('ui-selected');\n\t\t\t\tselectee.$element\n\t\t\t\t\t.removeClass(doSelect ? \"ui-unselecting\" : \"ui-selected\")\n\t\t\t\t\t.addClass(doSelect ? \"ui-selecting\" : \"ui-unselecting\");\n\t\t\t\tselectee.unselecting = !doSelect;\n\t\t\t\tselectee.selecting = doSelect;\n\t\t\t\tselectee.selected = doSelect;\n\t\t\t\t// selectable (UN)SELECTING callback\n\t\t\t\tif (doSelect) {\n\t\t\t\t\tself._trigger(\"selecting\", event, {\n\t\t\t\t\t\tselecting: selectee.element\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tself._trigger(\"unselecting\", event, {\n\t\t\t\t\t\tunselecting: selectee.element\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\n\t},\n\n\t_mouseDrag: function(event) {\n\t\tvar self = this;\n\t\tthis.dragged = true;\n\n\t\tif (this.options.disabled)\n\t\t\treturn;\n\n\t\tvar options = this.options;\n\n\t\tvar x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;\n\t\tif (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }\n\t\tif (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }\n\t\tthis.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});\n\n\t\tthis.selectees.each(function() {\n\t\t\tvar selectee = $.data(this, \"selectable-item\");\n\t\t\t//prevent helper from being selected if appendTo: selectable\n\t\t\tif (!selectee || selectee.element == self.element[0])\n\t\t\t\treturn;\n\t\t\tvar hit = false;\n\t\t\tif (options.tolerance == 'touch') {\n\t\t\t\thit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );\n\t\t\t} else if (options.tolerance == 'fit') {\n\t\t\t\thit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);\n\t\t\t}\n\n\t\t\tif (hit) {\n\t\t\t\t// SELECT\n\t\t\t\tif (selectee.selected) {\n\t\t\t\t\tselectee.$element.removeClass('ui-selected');\n\t\t\t\t\tselectee.selected = false;\n\t\t\t\t}\n\t\t\t\tif (selectee.unselecting) {\n\t\t\t\t\tselectee.$element.removeClass('ui-unselecting');\n\t\t\t\t\tselectee.unselecting = false;\n\t\t\t\t}\n\t\t\t\tif (!selectee.selecting) {\n\t\t\t\t\tselectee.$element.addClass('ui-selecting');\n\t\t\t\t\tselectee.selecting = true;\n\t\t\t\t\t// selectable SELECTING callback\n\t\t\t\t\tself._trigger(\"selecting\", event, {\n\t\t\t\t\t\tselecting: selectee.element\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// UNSELECT\n\t\t\t\tif (selectee.selecting) {\n\t\t\t\t\tif (event.metaKey && selectee.startselected) {\n\t\t\t\t\t\tselectee.$element.removeClass('ui-selecting');\n\t\t\t\t\t\tselectee.selecting = false;\n\t\t\t\t\t\tselectee.$element.addClass('ui-selected');\n\t\t\t\t\t\tselectee.selected = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tselectee.$element.removeClass('ui-selecting');\n\t\t\t\t\t\tselectee.selecting = false;\n\t\t\t\t\t\tif (selectee.startselected) {\n\t\t\t\t\t\t\tselectee.$element.addClass('ui-unselecting');\n\t\t\t\t\t\t\tselectee.unselecting = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// selectable UNSELECTING callback\n\t\t\t\t\t\tself._trigger(\"unselecting\", event, {\n\t\t\t\t\t\t\tunselecting: selectee.element\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (selectee.selected) {\n\t\t\t\t\tif (!event.metaKey && !selectee.startselected) {\n\t\t\t\t\t\tselectee.$element.removeClass('ui-selected');\n\t\t\t\t\t\tselectee.selected = false;\n\n\t\t\t\t\t\tselectee.$element.addClass('ui-unselecting');\n\t\t\t\t\t\tselectee.unselecting = true;\n\t\t\t\t\t\t// selectable UNSELECTING callback\n\t\t\t\t\t\tself._trigger(\"unselecting\", event, {\n\t\t\t\t\t\t\tunselecting: selectee.element\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn false;\n\t},\n\n\t_mouseStop: function(event) {\n\t\tvar self = this;\n\n\t\tthis.dragged = false;\n\n\t\tvar options = this.options;\n\n\t\t$('.ui-unselecting', this.element[0]).each(function() {\n\t\t\tvar selectee = $.data(this, \"selectable-item\");\n\t\t\tselectee.$element.removeClass('ui-unselecting');\n\t\t\tselectee.unselecting = false;\n\t\t\tselectee.startselected = false;\n\t\t\tself._trigger(\"unselected\", event, {\n\t\t\t\tunselected: selectee.element\n\t\t\t});\n\t\t});\n\t\t$('.ui-selecting', this.element[0]).each(function() {\n\t\t\tvar selectee = $.data(this, \"selectable-item\");\n\t\t\tselectee.$element.removeClass('ui-selecting').addClass('ui-selected');\n\t\t\tselectee.selecting = false;\n\t\t\tselectee.selected = true;\n\t\t\tselectee.startselected = true;\n\t\t\tself._trigger(\"selected\", event, {\n\t\t\t\tselected: selectee.element\n\t\t\t});\n\t\t});\n\t\tthis._trigger(\"stop\", event);\n\n\t\tthis.helper.remove();\n\n\t\treturn false;\n\t}\n\n});\n\n$.extend($.ui.selectable, {\n\tversion: \"1.8.6\"\n});\n\n})(jQuery);\n/*\n * jQuery UI Sortable 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Sortables\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.mouse.js\n *\tjquery.ui.widget.js\n */\n(function( $, undefined ) {\n\n$.widget(\"ui.sortable\", $.ui.mouse, {\n\twidgetEventPrefix: \"sort\",\n\toptions: {\n\t\tappendTo: \"parent\",\n\t\taxis: false,\n\t\tconnectWith: false,\n\t\tcontainment: false,\n\t\tcursor: 'auto',\n\t\tcursorAt: false,\n\t\tdropOnEmpty: true,\n\t\tforcePlaceholderSize: false,\n\t\tforceHelperSize: false,\n\t\tgrid: false,\n\t\thandle: false,\n\t\thelper: \"original\",\n\t\titems: '> *',\n\t\topacity: false,\n\t\tplaceholder: false,\n\t\trevert: false,\n\t\tscroll: true,\n\t\tscrollSensitivity: 20,\n\t\tscrollSpeed: 20,\n\t\tscope: \"default\",\n\t\ttolerance: \"intersect\",\n\t\tzIndex: 1000\n\t},\n\t_create: function() {\n\n\t\tvar o = this.options;\n\t\tthis.containerCache = {};\n\t\tthis.element.addClass(\"ui-sortable\");\n\n\t\t//Get the items\n\t\tthis.refresh();\n\n\t\t//Let's determine if the items are floating\n\t\tthis.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false;\n\n\t\t//Let's determine the parent's offset\n\t\tthis.offset = this.element.offset();\n\n\t\t//Initialize mouse events for interaction\n\t\tthis._mouseInit();\n\n\t},\n\n\tdestroy: function() {\n\t\tthis.element\n\t\t\t.removeClass(\"ui-sortable ui-sortable-disabled\")\n\t\t\t.removeData(\"sortable\")\n\t\t\t.unbind(\".sortable\");\n\t\tthis._mouseDestroy();\n\n\t\tfor ( var i = this.items.length - 1; i >= 0; i-- )\n\t\t\tthis.items[i].item.removeData(\"sortable-item\");\n\n\t\treturn this;\n\t},\n\n\t_setOption: function(key, value){\n\t\tif ( key === \"disabled\" ) {\n\t\t\tthis.options[ key ] = value;\n\t\n\t\t\tthis.widget()\n\t\t\t\t[ value ? \"addClass\" : \"removeClass\"]( \"ui-sortable-disabled\" );\n\t\t} else {\n\t\t\t// Don't call widget base _setOption for disable as it adds ui-state-disabled class\n\t\t\t$.Widget.prototype._setOption.apply(this, arguments);\n\t\t}\n\t},\n\n\t_mouseCapture: function(event, overrideHandle) {\n\n\t\tif (this.reverting) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif(this.options.disabled || this.options.type == 'static') return false;\n\n\t\t//We have to refresh the items data once first\n\t\tthis._refreshItems(event);\n\n\t\t//Find out if the clicked node (or one of its parents) is a actual item in this.items\n\t\tvar currentItem = null, self = this, nodes = $(event.target).parents().each(function() {\n\t\t\tif($.data(this, 'sortable-item') == self) {\n\t\t\t\tcurrentItem = $(this);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t\tif($.data(event.target, 'sortable-item') == self) currentItem = $(event.target);\n\n\t\tif(!currentItem) return false;\n\t\tif(this.options.handle && !overrideHandle) {\n\t\t\tvar validHandle = false;\n\n\t\t\t$(this.options.handle, currentItem).find(\"*\").andSelf().each(function() { if(this == event.target) validHandle = true; });\n\t\t\tif(!validHandle) return false;\n\t\t}\n\n\t\tthis.currentItem = currentItem;\n\t\tthis._removeCurrentsFromItems();\n\t\treturn true;\n\n\t},\n\n\t_mouseStart: function(event, overrideHandle, noActivation) {\n\n\t\tvar o = this.options, self = this;\n\t\tthis.currentContainer = this;\n\n\t\t//We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture\n\t\tthis.refreshPositions();\n\n\t\t//Create and append the visible helper\n\t\tthis.helper = this._createHelper(event);\n\n\t\t//Cache the helper size\n\t\tthis._cacheHelperProportions();\n\n\t\t/*\n\t\t * - Position generation -\n\t\t * This block generates everything position related - it's the core of draggables.\n\t\t */\n\n\t\t//Cache the margins of the original element\n\t\tthis._cacheMargins();\n\n\t\t//Get the next scrolling parent\n\t\tthis.scrollParent = this.helper.scrollParent();\n\n\t\t//The element's absolute position on the page minus margins\n\t\tthis.offset = this.currentItem.offset();\n\t\tthis.offset = {\n\t\t\ttop: this.offset.top - this.margins.top,\n\t\t\tleft: this.offset.left - this.margins.left\n\t\t};\n\n\t\t// Only after we got the offset, we can change the helper's position to absolute\n\t\t// TODO: Still need to figure out a way to make relative sorting possible\n\t\tthis.helper.css(\"position\", \"absolute\");\n\t\tthis.cssPosition = this.helper.css(\"position\");\n\n\t\t$.extend(this.offset, {\n\t\t\tclick: { //Where the click happened, relative to the element\n\t\t\t\tleft: event.pageX - this.offset.left,\n\t\t\t\ttop: event.pageY - this.offset.top\n\t\t\t},\n\t\t\tparent: this._getParentOffset(),\n\t\t\trelative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper\n\t\t});\n\n\t\t//Generate the original position\n\t\tthis.originalPosition = this._generatePosition(event);\n\t\tthis.originalPageX = event.pageX;\n\t\tthis.originalPageY = event.pageY;\n\n\t\t//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied\n\t\t(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));\n\n\t\t//Cache the former DOM position\n\t\tthis.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };\n\n\t\t//If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way\n\t\tif(this.helper[0] != this.currentItem[0]) {\n\t\t\tthis.currentItem.hide();\n\t\t}\n\n\t\t//Create the placeholder\n\t\tthis._createPlaceholder();\n\n\t\t//Set a containment if given in the options\n\t\tif(o.containment)\n\t\t\tthis._setContainment();\n\n\t\tif(o.cursor) { // cursor option\n\t\t\tif ($('body').css(\"cursor\")) this._storedCursor = $('body').css(\"cursor\");\n\t\t\t$('body').css(\"cursor\", o.cursor);\n\t\t}\n\n\t\tif(o.opacity) { // opacity option\n\t\t\tif (this.helper.css(\"opacity\")) this._storedOpacity = this.helper.css(\"opacity\");\n\t\t\tthis.helper.css(\"opacity\", o.opacity);\n\t\t}\n\n\t\tif(o.zIndex) { // zIndex option\n\t\t\tif (this.helper.css(\"zIndex\")) this._storedZIndex = this.helper.css(\"zIndex\");\n\t\t\tthis.helper.css(\"zIndex\", o.zIndex);\n\t\t}\n\n\t\t//Prepare scrolling\n\t\tif(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')\n\t\t\tthis.overflowOffset = this.scrollParent.offset();\n\n\t\t//Call callbacks\n\t\tthis._trigger(\"start\", event, this._uiHash());\n\n\t\t//Recache the helper size\n\t\tif(!this._preserveHelperProportions)\n\t\t\tthis._cacheHelperProportions();\n\n\n\t\t//Post 'activate' events to possible containers\n\t\tif(!noActivation) {\n\t\t\t for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger(\"activate\", event, self._uiHash(this)); }\n\t\t}\n\n\t\t//Prepare possible droppables\n\t\tif($.ui.ddmanager)\n\t\t\t$.ui.ddmanager.current = this;\n\n\t\tif ($.ui.ddmanager && !o.dropBehaviour)\n\t\t\t$.ui.ddmanager.prepareOffsets(this, event);\n\n\t\tthis.dragging = true;\n\n\t\tthis.helper.addClass(\"ui-sortable-helper\");\n\t\tthis._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position\n\t\treturn true;\n\n\t},\n\n\t_mouseDrag: function(event) {\n\n\t\t//Compute the helpers position\n\t\tthis.position = this._generatePosition(event);\n\t\tthis.positionAbs = this._convertPositionTo(\"absolute\");\n\n\t\tif (!this.lastPositionAbs) {\n\t\t\tthis.lastPositionAbs = this.positionAbs;\n\t\t}\n\n\t\t//Do scrolling\n\t\tif(this.options.scroll) {\n\t\t\tvar o = this.options, scrolled = false;\n\t\t\tif(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {\n\n\t\t\t\tif((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)\n\t\t\t\t\tthis.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;\n\t\t\t\telse if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)\n\t\t\t\t\tthis.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;\n\n\t\t\t\tif((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)\n\t\t\t\t\tthis.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;\n\t\t\t\telse if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)\n\t\t\t\t\tthis.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;\n\n\t\t\t} else {\n\n\t\t\t\tif(event.pageY - $(document).scrollTop() < o.scrollSensitivity)\n\t\t\t\t\tscrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);\n\t\t\t\telse if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)\n\t\t\t\t\tscrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);\n\n\t\t\t\tif(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)\n\t\t\t\t\tscrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);\n\t\t\t\telse if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)\n\t\t\t\t\tscrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);\n\n\t\t\t}\n\n\t\t\tif(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)\n\t\t\t\t$.ui.ddmanager.prepareOffsets(this, event);\n\t\t}\n\n\t\t//Regenerate the absolute position used for position checks\n\t\tthis.positionAbs = this._convertPositionTo(\"absolute\");\n\n\t\t//Set the helper position\n\t\tif(!this.options.axis || this.options.axis != \"y\") this.helper[0].style.left = this.position.left+'px';\n\t\tif(!this.options.axis || this.options.axis != \"x\") this.helper[0].style.top = this.position.top+'px';\n\n\t\t//Rearrange\n\t\tfor (var i = this.items.length - 1; i >= 0; i--) {\n\n\t\t\t//Cache variables and intersection, continue if no intersection\n\t\t\tvar item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);\n\t\t\tif (!intersection) continue;\n\n\t\t\tif(itemElement != this.currentItem[0] //cannot intersect with itself\n\t\t\t\t&&\tthis.placeholder[intersection == 1 ? \"next\" : \"prev\"]()[0] != itemElement //no useless actions that have been done before\n\t\t\t\t&&\t!$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked\n\t\t\t\t&& (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)\n\t\t\t\t//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container\n\t\t\t) {\n\n\t\t\t\tthis.direction = intersection == 1 ? \"down\" : \"up\";\n\n\t\t\t\tif (this.options.tolerance == \"pointer\" || this._intersectsWithSides(item)) {\n\t\t\t\t\tthis._rearrange(event, item);\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tthis._trigger(\"change\", event, this._uiHash());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t//Post events to containers\n\t\tthis._contactContainers(event);\n\n\t\t//Interconnect with droppables\n\t\tif($.ui.ddmanager) $.ui.ddmanager.drag(this, event);\n\n\t\t//Call callbacks\n\t\tthis._trigger('sort', event, this._uiHash());\n\n\t\tthis.lastPositionAbs = this.positionAbs;\n\t\treturn false;\n\n\t},\n\n\t_mouseStop: function(event, noPropagation) {\n\n\t\tif(!event) return;\n\n\t\t//If we are using droppables, inform the manager about the drop\n\t\tif ($.ui.ddmanager && !this.options.dropBehaviour)\n\t\t\t$.ui.ddmanager.drop(this, event);\n\n\t\tif(this.options.revert) {\n\t\t\tvar self = this;\n\t\t\tvar cur = self.placeholder.offset();\n\n\t\t\tself.reverting = true;\n\n\t\t\t$(this.helper).animate({\n\t\t\t\tleft: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),\n\t\t\t\ttop: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)\n\t\t\t}, parseInt(this.options.revert, 10) || 500, function() {\n\t\t\t\tself._clear(event);\n\t\t\t});\n\t\t} else {\n\t\t\tthis._clear(event, noPropagation);\n\t\t}\n\n\t\treturn false;\n\n\t},\n\n\tcancel: function() {\n\n\t\tvar self = this;\n\n\t\tif(this.dragging) {\n\n\t\t\tthis._mouseUp();\n\n\t\t\tif(this.options.helper == \"original\")\n\t\t\t\tthis.currentItem.css(this._storedCSS).removeClass(\"ui-sortable-helper\");\n\t\t\telse\n\t\t\t\tthis.currentItem.show();\n\n\t\t\t//Post deactivating events to containers\n\t\t\tfor (var i = this.containers.length - 1; i >= 0; i--){\n\t\t\t\tthis.containers[i]._trigger(\"deactivate\", null, self._uiHash(this));\n\t\t\t\tif(this.containers[i].containerCache.over) {\n\t\t\t\t\tthis.containers[i]._trigger(\"out\", null, self._uiHash(this));\n\t\t\t\t\tthis.containers[i].containerCache.over = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\t//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!\n\t\tif(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);\n\t\tif(this.options.helper != \"original\" && this.helper && this.helper[0].parentNode) this.helper.remove();\n\n\t\t$.extend(this, {\n\t\t\thelper: null,\n\t\t\tdragging: false,\n\t\t\treverting: false,\n\t\t\t_noFinalSort: null\n\t\t});\n\n\t\tif(this.domPosition.prev) {\n\t\t\t$(this.domPosition.prev).after(this.currentItem);\n\t\t} else {\n\t\t\t$(this.domPosition.parent).prepend(this.currentItem);\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tserialize: function(o) {\n\n\t\tvar items = this._getItemsAsjQuery(o && o.connected);\n\t\tvar str = []; o = o || {};\n\n\t\t$(items).each(function() {\n\t\t\tvar res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));\n\t\t\tif(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));\n\t\t});\n\n\t\tif(!str.length && o.key) {\n\t\t\tstr.push(o.key + '=');\n\t\t}\n\n\t\treturn str.join('&');\n\n\t},\n\n\ttoArray: function(o) {\n\n\t\tvar items = this._getItemsAsjQuery(o && o.connected);\n\t\tvar ret = []; o = o || {};\n\n\t\titems.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });\n\t\treturn ret;\n\n\t},\n\n\t/* Be careful with the following core functions */\n\t_intersectsWith: function(item) {\n\n\t\tvar x1 = this.positionAbs.left,\n\t\t\tx2 = x1 + this.helperProportions.width,\n\t\t\ty1 = this.positionAbs.top,\n\t\t\ty2 = y1 + this.helperProportions.height;\n\n\t\tvar l = item.left,\n\t\t\tr = l + item.width,\n\t\t\tt = item.top,\n\t\t\tb = t + item.height;\n\n\t\tvar dyClick = this.offset.click.top,\n\t\t\tdxClick = this.offset.click.left;\n\n\t\tvar isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;\n\n\t\tif(\t   this.options.tolerance == \"pointer\"\n\t\t\t|| this.options.forcePointerForContainers\n\t\t\t|| (this.options.tolerance != \"pointer\" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])\n\t\t) {\n\t\t\treturn isOverElement;\n\t\t} else {\n\n\t\t\treturn (l < x1 + (this.helperProportions.width / 2) // Right Half\n\t\t\t\t&& x2 - (this.helperProportions.width / 2) < r // Left Half\n\t\t\t\t&& t < y1 + (this.helperProportions.height / 2) // Bottom Half\n\t\t\t\t&& y2 - (this.helperProportions.height / 2) < b ); // Top Half\n\n\t\t}\n\t},\n\n\t_intersectsWithPointer: function(item) {\n\n\t\tvar isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),\n\t\t\tisOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),\n\t\t\tisOverElement = isOverElementHeight && isOverElementWidth,\n\t\t\tverticalDirection = this._getDragVerticalDirection(),\n\t\t\thorizontalDirection = this._getDragHorizontalDirection();\n\n\t\tif (!isOverElement)\n\t\t\treturn false;\n\n\t\treturn this.floating ?\n\t\t\t( ((horizontalDirection && horizontalDirection == \"right\") || verticalDirection == \"down\") ? 2 : 1 )\n\t\t\t: ( verticalDirection && (verticalDirection == \"down\" ? 2 : 1) );\n\n\t},\n\n\t_intersectsWithSides: function(item) {\n\n\t\tvar isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),\n\t\t\tisOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),\n\t\t\tverticalDirection = this._getDragVerticalDirection(),\n\t\t\thorizontalDirection = this._getDragHorizontalDirection();\n\n\t\tif (this.floating && horizontalDirection) {\n\t\t\treturn ((horizontalDirection == \"right\" && isOverRightHalf) || (horizontalDirection == \"left\" && !isOverRightHalf));\n\t\t} else {\n\t\t\treturn verticalDirection && ((verticalDirection == \"down\" && isOverBottomHalf) || (verticalDirection == \"up\" && !isOverBottomHalf));\n\t\t}\n\n\t},\n\n\t_getDragVerticalDirection: function() {\n\t\tvar delta = this.positionAbs.top - this.lastPositionAbs.top;\n\t\treturn delta != 0 && (delta > 0 ? \"down\" : \"up\");\n\t},\n\n\t_getDragHorizontalDirection: function() {\n\t\tvar delta = this.positionAbs.left - this.lastPositionAbs.left;\n\t\treturn delta != 0 && (delta > 0 ? \"right\" : \"left\");\n\t},\n\n\trefresh: function(event) {\n\t\tthis._refreshItems(event);\n\t\tthis.refreshPositions();\n\t\treturn this;\n\t},\n\n\t_connectWith: function() {\n\t\tvar options = this.options;\n\t\treturn options.connectWith.constructor == String\n\t\t\t? [options.connectWith]\n\t\t\t: options.connectWith;\n\t},\n\t\n\t_getItemsAsjQuery: function(connected) {\n\n\t\tvar self = this;\n\t\tvar items = [];\n\t\tvar queries = [];\n\t\tvar connectWith = this._connectWith();\n\n\t\tif(connectWith && connected) {\n\t\t\tfor (var i = connectWith.length - 1; i >= 0; i--){\n\t\t\t\tvar cur = $(connectWith[i]);\n\t\t\t\tfor (var j = cur.length - 1; j >= 0; j--){\n\t\t\t\t\tvar inst = $.data(cur[j], 'sortable');\n\t\t\t\t\tif(inst && inst != this && !inst.options.disabled) {\n\t\t\t\t\t\tqueries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(\".ui-sortable-helper\").not('.ui-sortable-placeholder'), inst]);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\tqueries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(\".ui-sortable-helper\").not('.ui-sortable-placeholder'), this]);\n\n\t\tfor (var i = queries.length - 1; i >= 0; i--){\n\t\t\tqueries[i][0].each(function() {\n\t\t\t\titems.push(this);\n\t\t\t});\n\t\t};\n\n\t\treturn $(items);\n\n\t},\n\n\t_removeCurrentsFromItems: function() {\n\n\t\tvar list = this.currentItem.find(\":data(sortable-item)\");\n\n\t\tfor (var i=0; i < this.items.length; i++) {\n\n\t\t\tfor (var j=0; j < list.length; j++) {\n\t\t\t\tif(list[j] == this.items[i].item[0])\n\t\t\t\t\tthis.items.splice(i,1);\n\t\t\t};\n\n\t\t};\n\n\t},\n\n\t_refreshItems: function(event) {\n\n\t\tthis.items = [];\n\t\tthis.containers = [this];\n\t\tvar items = this.items;\n\t\tvar self = this;\n\t\tvar queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];\n\t\tvar connectWith = this._connectWith();\n\n\t\tif(connectWith) {\n\t\t\tfor (var i = connectWith.length - 1; i >= 0; i--){\n\t\t\t\tvar cur = $(connectWith[i]);\n\t\t\t\tfor (var j = cur.length - 1; j >= 0; j--){\n\t\t\t\t\tvar inst = $.data(cur[j], 'sortable');\n\t\t\t\t\tif(inst && inst != this && !inst.options.disabled) {\n\t\t\t\t\t\tqueries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);\n\t\t\t\t\t\tthis.containers.push(inst);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t\tfor (var i = queries.length - 1; i >= 0; i--) {\n\t\t\tvar targetData = queries[i][1];\n\t\t\tvar _queries = queries[i][0];\n\n\t\t\tfor (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {\n\t\t\t\tvar item = $(_queries[j]);\n\n\t\t\t\titem.data('sortable-item', targetData); // Data for target checking (mouse manager)\n\n\t\t\t\titems.push({\n\t\t\t\t\titem: item,\n\t\t\t\t\tinstance: targetData,\n\t\t\t\t\twidth: 0, height: 0,\n\t\t\t\t\tleft: 0, top: 0\n\t\t\t\t});\n\t\t\t};\n\t\t};\n\n\t},\n\n\trefreshPositions: function(fast) {\n\n\t\t//This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change\n\t\tif(this.offsetParent && this.helper) {\n\t\t\tthis.offset.parent = this._getParentOffset();\n\t\t}\n\n\t\tfor (var i = this.items.length - 1; i >= 0; i--){\n\t\t\tvar item = this.items[i];\n\n\t\t\tvar t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;\n\n\t\t\tif (!fast) {\n\t\t\t\titem.width = t.outerWidth();\n\t\t\t\titem.height = t.outerHeight();\n\t\t\t}\n\n\t\t\tvar p = t.offset();\n\t\t\titem.left = p.left;\n\t\t\titem.top = p.top;\n\t\t};\n\n\t\tif(this.options.custom && this.options.custom.refreshContainers) {\n\t\t\tthis.options.custom.refreshContainers.call(this);\n\t\t} else {\n\t\t\tfor (var i = this.containers.length - 1; i >= 0; i--){\n\t\t\t\tvar p = this.containers[i].element.offset();\n\t\t\t\tthis.containers[i].containerCache.left = p.left;\n\t\t\t\tthis.containers[i].containerCache.top = p.top;\n\t\t\t\tthis.containers[i].containerCache.width\t= this.containers[i].element.outerWidth();\n\t\t\t\tthis.containers[i].containerCache.height = this.containers[i].element.outerHeight();\n\t\t\t};\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t_createPlaceholder: function(that) {\n\n\t\tvar self = that || this, o = self.options;\n\n\t\tif(!o.placeholder || o.placeholder.constructor == String) {\n\t\t\tvar className = o.placeholder;\n\t\t\to.placeholder = {\n\t\t\t\telement: function() {\n\n\t\t\t\t\tvar el = $(document.createElement(self.currentItem[0].nodeName))\n\t\t\t\t\t\t.addClass(className || self.currentItem[0].className+\" ui-sortable-placeholder\")\n\t\t\t\t\t\t.removeClass(\"ui-sortable-helper\")[0];\n\n\t\t\t\t\tif(!className)\n\t\t\t\t\t\tel.style.visibility = \"hidden\";\n\n\t\t\t\t\treturn el;\n\t\t\t\t},\n\t\t\t\tupdate: function(container, p) {\n\n\t\t\t\t\t// 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that\n\t\t\t\t\t// 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified\n\t\t\t\t\tif(className && !o.forcePlaceholderSize) return;\n\n\t\t\t\t\t//If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item\n\t\t\t\t\tif(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); };\n\t\t\t\t\tif(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); };\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t//Create the placeholder\n\t\tself.placeholder = $(o.placeholder.element.call(self.element, self.currentItem));\n\n\t\t//Append it after the actual current item\n\t\tself.currentItem.after(self.placeholder);\n\n\t\t//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)\n\t\to.placeholder.update(self, self.placeholder);\n\n\t},\n\n\t_contactContainers: function(event) {\n\t\t\n\t\t// get innermost container that intersects with item \n\t\tvar innermostContainer = null, innermostIndex = null;\t\t\n\t\t\n\t\t\n\t\tfor (var i = this.containers.length - 1; i >= 0; i--){\n\n\t\t\t// never consider a container that's located within the item itself \n\t\t\tif($.ui.contains(this.currentItem[0], this.containers[i].element[0]))\n\t\t\t\tcontinue;\n\n\t\t\tif(this._intersectsWith(this.containers[i].containerCache)) {\n\n\t\t\t\t// if we've already found a container and it's more \"inner\" than this, then continue \n\t\t\t\tif(innermostContainer && $.ui.contains(this.containers[i].element[0], innermostContainer.element[0]))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tinnermostContainer = this.containers[i]; \n\t\t\t\tinnermostIndex = i;\n\t\t\t\t\t\n\t\t\t} else {\n\t\t\t\t// container doesn't intersect. trigger \"out\" event if necessary \n\t\t\t\tif(this.containers[i].containerCache.over) {\n\t\t\t\t\tthis.containers[i]._trigger(\"out\", event, this._uiHash(this));\n\t\t\t\t\tthis.containers[i].containerCache.over = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\t\n\t\t// if no intersecting containers found, return \n\t\tif(!innermostContainer) return; \n\n\t\t// move the item into the container if it's not there already\n\t\tif(this.containers.length === 1) {\n\t\t\tthis.containers[innermostIndex]._trigger(\"over\", event, this._uiHash(this));\n\t\t\tthis.containers[innermostIndex].containerCache.over = 1;\n\t\t} else if(this.currentContainer != this.containers[innermostIndex]) { \n\n\t\t\t//When entering a new container, we will find the item with the least distance and append our item near it \n\t\t\tvar dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top']; \n\t\t\tfor (var j = this.items.length - 1; j >= 0; j--) { \n\t\t\t\tif(!$.ui.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue; \n\t\t\t\tvar cur = this.items[j][this.containers[innermostIndex].floating ? 'left' : 'top']; \n\t\t\t\tif(Math.abs(cur - base) < dist) { \n\t\t\t\t\tdist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; \n\t\t\t\t} \n\t\t\t} \n\n\t\t\tif(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled \n\t\t\t\treturn; \n\n\t\t\tthis.currentContainer = this.containers[innermostIndex]; \n\t\t\titemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); \n\t\t\tthis._trigger(\"change\", event, this._uiHash()); \n\t\t\tthis.containers[innermostIndex]._trigger(\"change\", event, this._uiHash(this)); \n\n\t\t\t//Update the placeholder \n\t\t\tthis.options.placeholder.update(this.currentContainer, this.placeholder); \n\t\t\n\t\t\tthis.containers[innermostIndex]._trigger(\"over\", event, this._uiHash(this)); \n\t\t\tthis.containers[innermostIndex].containerCache.over = 1;\n\t\t} \n\t\n\t\t\n\t},\n\n\t_createHelper: function(event) {\n\n\t\tvar o = this.options;\n\t\tvar helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);\n\n\t\tif(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already\n\t\t\t$(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);\n\n\t\tif(helper[0] == this.currentItem[0])\n\t\t\tthis._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css(\"position\"), top: this.currentItem.css(\"top\"), left: this.currentItem.css(\"left\") };\n\n\t\tif(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());\n\t\tif(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());\n\n\t\treturn helper;\n\n\t},\n\n\t_adjustOffsetFromHelper: function(obj) {\n\t\tif (typeof obj == 'string') {\n\t\t\tobj = obj.split(' ');\n\t\t}\n\t\tif ($.isArray(obj)) {\n\t\t\tobj = {left: +obj[0], top: +obj[1] || 0};\n\t\t}\n\t\tif ('left' in obj) {\n\t\t\tthis.offset.click.left = obj.left + this.margins.left;\n\t\t}\n\t\tif ('right' in obj) {\n\t\t\tthis.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;\n\t\t}\n\t\tif ('top' in obj) {\n\t\t\tthis.offset.click.top = obj.top + this.margins.top;\n\t\t}\n\t\tif ('bottom' in obj) {\n\t\t\tthis.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;\n\t\t}\n\t},\n\n\t_getParentOffset: function() {\n\n\n\t\t//Get the offsetParent and cache its position\n\t\tthis.offsetParent = this.helper.offsetParent();\n\t\tvar po = this.offsetParent.offset();\n\n\t\t// This is a special case where we need to modify a offset calculated on start, since the following happened:\n\t\t// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent\n\t\t// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that\n\t\t//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag\n\t\tif(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {\n\t\t\tpo.left += this.scrollParent.scrollLeft();\n\t\t\tpo.top += this.scrollParent.scrollTop();\n\t\t}\n\n\t\tif((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information\n\t\t|| (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix\n\t\t\tpo = { top: 0, left: 0 };\n\n\t\treturn {\n\t\t\ttop: po.top + (parseInt(this.offsetParent.css(\"borderTopWidth\"),10) || 0),\n\t\t\tleft: po.left + (parseInt(this.offsetParent.css(\"borderLeftWidth\"),10) || 0)\n\t\t};\n\n\t},\n\n\t_getRelativeOffset: function() {\n\n\t\tif(this.cssPosition == \"relative\") {\n\t\t\tvar p = this.currentItem.position();\n\t\t\treturn {\n\t\t\t\ttop: p.top - (parseInt(this.helper.css(\"top\"),10) || 0) + this.scrollParent.scrollTop(),\n\t\t\t\tleft: p.left - (parseInt(this.helper.css(\"left\"),10) || 0) + this.scrollParent.scrollLeft()\n\t\t\t};\n\t\t} else {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t},\n\n\t_cacheMargins: function() {\n\t\tthis.margins = {\n\t\t\tleft: (parseInt(this.currentItem.css(\"marginLeft\"),10) || 0),\n\t\t\ttop: (parseInt(this.currentItem.css(\"marginTop\"),10) || 0)\n\t\t};\n\t},\n\n\t_cacheHelperProportions: function() {\n\t\tthis.helperProportions = {\n\t\t\twidth: this.helper.outerWidth(),\n\t\t\theight: this.helper.outerHeight()\n\t\t};\n\t},\n\n\t_setContainment: function() {\n\n\t\tvar o = this.options;\n\t\tif(o.containment == 'parent') o.containment = this.helper[0].parentNode;\n\t\tif(o.containment == 'document' || o.containment == 'window') this.containment = [\n\t\t\t0 - this.offset.relative.left - this.offset.parent.left,\n\t\t\t0 - this.offset.relative.top - this.offset.parent.top,\n\t\t\t$(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,\n\t\t\t($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top\n\t\t];\n\n\t\tif(!(/^(document|window|parent)$/).test(o.containment)) {\n\t\t\tvar ce = $(o.containment)[0];\n\t\t\tvar co = $(o.containment).offset();\n\t\t\tvar over = ($(ce).css(\"overflow\") != 'hidden');\n\n\t\t\tthis.containment = [\n\t\t\t\tco.left + (parseInt($(ce).css(\"borderLeftWidth\"),10) || 0) + (parseInt($(ce).css(\"paddingLeft\"),10) || 0) - this.margins.left,\n\t\t\t\tco.top + (parseInt($(ce).css(\"borderTopWidth\"),10) || 0) + (parseInt($(ce).css(\"paddingTop\"),10) || 0) - this.margins.top,\n\t\t\t\tco.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css(\"borderLeftWidth\"),10) || 0) - (parseInt($(ce).css(\"paddingRight\"),10) || 0) - this.helperProportions.width - this.margins.left,\n\t\t\t\tco.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css(\"borderTopWidth\"),10) || 0) - (parseInt($(ce).css(\"paddingBottom\"),10) || 0) - this.helperProportions.height - this.margins.top\n\t\t\t];\n\t\t}\n\n\t},\n\n\t_convertPositionTo: function(d, pos) {\n\n\t\tif(!pos) pos = this.position;\n\t\tvar mod = d == \"absolute\" ? 1 : -1;\n\t\tvar o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);\n\n\t\treturn {\n\t\t\ttop: (\n\t\t\t\tpos.top\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\t+ this.offset.relative.top * mod\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\t+ this.offset.parent.top * mod\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t- ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)\n\t\t\t),\n\t\t\tleft: (\n\t\t\t\tpos.left\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\t+ this.offset.relative.left * mod\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\t+ this.offset.parent.left * mod\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t- ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)\n\t\t\t)\n\t\t};\n\n\t},\n\n\t_generatePosition: function(event) {\n\n\t\tvar o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);\n\n\t\t// This is another very weird special case that only happens for relative elements:\n\t\t// 1. If the css position is relative\n\t\t// 2. and the scroll parent is the document or similar to the offset parent\n\t\t// we have to refresh the relative offset during the scroll so there are no jumps\n\t\tif(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {\n\t\t\tthis.offset.relative = this._getRelativeOffset();\n\t\t}\n\n\t\tvar pageX = event.pageX;\n\t\tvar pageY = event.pageY;\n\n\t\t/*\n\t\t * - Position constraining -\n\t\t * Constrain the position to a mix of grid, containment.\n\t\t */\n\n\t\tif(this.originalPosition) { //If we are not dragging yet, we won't check for options\n\n\t\t\tif(this.containment) {\n\t\t\t\tif(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;\n\t\t\t\tif(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;\n\t\t\t\tif(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;\n\t\t\t\tif(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;\n\t\t\t}\n\n\t\t\tif(o.grid) {\n\t\t\t\tvar top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];\n\t\t\t\tpageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;\n\n\t\t\t\tvar left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];\n\t\t\t\tpageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\t\t\ttop: (\n\t\t\t\tpageY\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\t- this.offset.click.top\t\t\t\t\t\t\t\t\t\t\t\t\t// Click offset (relative to the element)\n\t\t\t\t- this.offset.relative.top\t\t\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\t- this.offset.parent.top\t\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t+ ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))\n\t\t\t),\n\t\t\tleft: (\n\t\t\t\tpageX\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// The absolute mouse position\n\t\t\t\t- this.offset.click.left\t\t\t\t\t\t\t\t\t\t\t\t// Click offset (relative to the element)\n\t\t\t\t- this.offset.relative.left\t\t\t\t\t\t\t\t\t\t\t\t// Only for relative positioned nodes: Relative offset from element to offset parent\n\t\t\t\t- this.offset.parent.left\t\t\t\t\t\t\t\t\t\t\t\t// The offsetParent's offset without borders (offset + border)\n\t\t\t\t+ ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))\n\t\t\t)\n\t\t};\n\n\t},\n\n\t_rearrange: function(event, i, a, hardRefresh) {\n\n\t\ta ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));\n\n\t\t//Various things done here to improve the performance:\n\t\t// 1. we create a setTimeout, that calls refreshPositions\n\t\t// 2. on the instance, we have a counter variable, that get's higher after every append\n\t\t// 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same\n\t\t// 4. this lets only the last addition to the timeout stack through\n\t\tthis.counter = this.counter ? ++this.counter : 1;\n\t\tvar self = this, counter = this.counter;\n\n\t\twindow.setTimeout(function() {\n\t\t\tif(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove\n\t\t},0);\n\n\t},\n\n\t_clear: function(event, noPropagation) {\n\n\t\tthis.reverting = false;\n\t\t// We delay all events that have to be triggered to after the point where the placeholder has been removed and\n\t\t// everything else normalized again\n\t\tvar delayedTriggers = [], self = this;\n\n\t\t// We first have to update the dom position of the actual currentItem\n\t\t// Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)\n\t\tif(!this._noFinalSort && this.currentItem[0].parentNode) this.placeholder.before(this.currentItem);\n\t\tthis._noFinalSort = null;\n\n\t\tif(this.helper[0] == this.currentItem[0]) {\n\t\t\tfor(var i in this._storedCSS) {\n\t\t\t\tif(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';\n\t\t\t}\n\t\t\tthis.currentItem.css(this._storedCSS).removeClass(\"ui-sortable-helper\");\n\t\t} else {\n\t\t\tthis.currentItem.show();\n\t\t}\n\n\t\tif(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger(\"receive\", event, this._uiHash(this.fromOutside)); });\n\t\tif((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(\".ui-sortable-helper\")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger(\"update\", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed\n\t\tif(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element\n\t\t\tif(!noPropagation) delayedTriggers.push(function(event) { this._trigger(\"remove\", event, this._uiHash()); });\n\t\t\tfor (var i = this.containers.length - 1; i >= 0; i--){\n\t\t\t\tif($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) {\n\t\t\t\t\tdelayedTriggers.push((function(c) { return function(event) { c._trigger(\"receive\", event, this._uiHash(this)); };  }).call(this, this.containers[i]));\n\t\t\t\t\tdelayedTriggers.push((function(c) { return function(event) { c._trigger(\"update\", event, this._uiHash(this));  }; }).call(this, this.containers[i]));\n\t\t\t\t}\n\t\t\t};\n\t\t};\n\n\t\t//Post events to containers\n\t\tfor (var i = this.containers.length - 1; i >= 0; i--){\n\t\t\tif(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger(\"deactivate\", event, this._uiHash(this)); };  }).call(this, this.containers[i]));\n\t\t\tif(this.containers[i].containerCache.over) {\n\t\t\t\tdelayedTriggers.push((function(c) { return function(event) { c._trigger(\"out\", event, this._uiHash(this)); };  }).call(this, this.containers[i]));\n\t\t\t\tthis.containers[i].containerCache.over = 0;\n\t\t\t}\n\t\t}\n\n\t\t//Do what was originally in plugins\n\t\tif(this._storedCursor) $('body').css(\"cursor\", this._storedCursor); //Reset cursor\n\t\tif(this._storedOpacity) this.helper.css(\"opacity\", this._storedOpacity); //Reset opacity\n\t\tif(this._storedZIndex) this.helper.css(\"zIndex\", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index\n\n\t\tthis.dragging = false;\n\t\tif(this.cancelHelperRemoval) {\n\t\t\tif(!noPropagation) {\n\t\t\t\tthis._trigger(\"beforeStop\", event, this._uiHash());\n\t\t\t\tfor (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events\n\t\t\t\tthis._trigger(\"stop\", event, this._uiHash());\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tif(!noPropagation) this._trigger(\"beforeStop\", event, this._uiHash());\n\n\t\t//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!\n\t\tthis.placeholder[0].parentNode.removeChild(this.placeholder[0]);\n\n\t\tif(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;\n\n\t\tif(!noPropagation) {\n\t\t\tfor (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events\n\t\t\tthis._trigger(\"stop\", event, this._uiHash());\n\t\t}\n\n\t\tthis.fromOutside = false;\n\t\treturn true;\n\n\t},\n\n\t_trigger: function() {\n\t\tif ($.Widget.prototype._trigger.apply(this, arguments) === false) {\n\t\t\tthis.cancel();\n\t\t}\n\t},\n\n\t_uiHash: function(inst) {\n\t\tvar self = inst || this;\n\t\treturn {\n\t\t\thelper: self.helper,\n\t\t\tplaceholder: self.placeholder || $([]),\n\t\t\tposition: self.position,\n\t\t\toriginalPosition: self.originalPosition,\n\t\t\toffset: self.positionAbs,\n\t\t\titem: self.currentItem,\n\t\t\tsender: inst ? inst.element : null\n\t\t};\n\t}\n\n});\n\n$.extend($.ui.sortable, {\n\tversion: \"1.8.6\"\n});\n\n})(jQuery);\n/*\n * jQuery UI Accordion 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Accordion\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.widget.js\n */\n(function( $, undefined ) {\n\n$.widget( \"ui.accordion\", {\n\toptions: {\n\t\tactive: 0,\n\t\tanimated: \"slide\",\n\t\tautoHeight: true,\n\t\tclearStyle: false,\n\t\tcollapsible: false,\n\t\tevent: \"click\",\n\t\tfillSpace: false,\n\t\theader: \"> li > :first-child,> :not(li):even\",\n\t\ticons: {\n\t\t\theader: \"ui-icon-triangle-1-e\",\n\t\t\theaderSelected: \"ui-icon-triangle-1-s\"\n\t\t},\n\t\tnavigation: false,\n\t\tnavigationFilter: function() {\n\t\t\treturn this.href.toLowerCase() === location.href.toLowerCase();\n\t\t}\n\t},\n\n\t_create: function() {\n\t\tvar self = this,\n\t\t\toptions = self.options;\n\n\t\tself.running = 0;\n\n\t\tself.element\n\t\t\t.addClass( \"ui-accordion ui-widget ui-helper-reset\" )\n\t\t\t// in lack of child-selectors in CSS\n\t\t\t// we need to mark top-LIs in a UL-accordion for some IE-fix\n\t\t\t.children( \"li\" )\n\t\t\t\t.addClass( \"ui-accordion-li-fix\" );\n\n\t\tself.headers = self.element.find( options.header )\n\t\t\t.addClass( \"ui-accordion-header ui-helper-reset ui-state-default ui-corner-all\" )\n\t\t\t.bind( \"mouseenter.accordion\", function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t$( this ).addClass( \"ui-state-hover\" );\n\t\t\t})\n\t\t\t.bind( \"mouseleave.accordion\", function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t$( this ).removeClass( \"ui-state-hover\" );\n\t\t\t})\n\t\t\t.bind( \"focus.accordion\", function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t$( this ).addClass( \"ui-state-focus\" );\n\t\t\t})\n\t\t\t.bind( \"blur.accordion\", function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t$( this ).removeClass( \"ui-state-focus\" );\n\t\t\t});\n\n\t\tself.headers.next()\n\t\t\t.addClass( \"ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom\" );\n\n\t\tif ( options.navigation ) {\n\t\t\tvar current = self.element.find( \"a\" ).filter( options.navigationFilter ).eq( 0 );\n\t\t\tif ( current.length ) {\n\t\t\t\tvar header = current.closest( \".ui-accordion-header\" );\n\t\t\t\tif ( header.length ) {\n\t\t\t\t\t// anchor within header\n\t\t\t\t\tself.active = header;\n\t\t\t\t} else {\n\t\t\t\t\t// anchor within content\n\t\t\t\t\tself.active = current.closest( \".ui-accordion-content\" ).prev();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tself.active = self._findActive( self.active || options.active )\n\t\t\t.addClass( \"ui-state-default ui-state-active\" )\n\t\t\t.toggleClass( \"ui-corner-all\" )\n\t\t\t.toggleClass( \"ui-corner-top\" );\n\t\tself.active.next().addClass( \"ui-accordion-content-active\" );\n\n\t\tself._createIcons();\n\t\tself.resize();\n\t\t\n\t\t// ARIA\n\t\tself.element.attr( \"role\", \"tablist\" );\n\n\t\tself.headers\n\t\t\t.attr( \"role\", \"tab\" )\n\t\t\t.bind( \"keydown.accordion\", function( event ) {\n\t\t\t\treturn self._keydown( event );\n\t\t\t})\n\t\t\t.next()\n\t\t\t\t.attr( \"role\", \"tabpanel\" );\n\n\t\tself.headers\n\t\t\t.not( self.active || \"\" )\n\t\t\t.attr({\n\t\t\t\t\"aria-expanded\": \"false\",\n\t\t\t\ttabIndex: -1\n\t\t\t})\n\t\t\t.next()\n\t\t\t\t.hide();\n\n\t\t// make sure at least one header is in the tab order\n\t\tif ( !self.active.length ) {\n\t\t\tself.headers.eq( 0 ).attr( \"tabIndex\", 0 );\n\t\t} else {\n\t\t\tself.active\n\t\t\t\t.attr({\n\t\t\t\t\t\"aria-expanded\": \"true\",\n\t\t\t\t\ttabIndex: 0\n\t\t\t\t});\n\t\t}\n\n\t\t// only need links in tab order for Safari\n\t\tif ( !$.browser.safari ) {\n\t\t\tself.headers.find( \"a\" ).attr( \"tabIndex\", -1 );\n\t\t}\n\n\t\tif ( options.event ) {\n\t\t\tself.headers.bind( options.event.split(\" \").join(\".accordion \") + \".accordion\", function(event) {\n\t\t\t\tself._clickHandler.call( self, event, this );\n\t\t\t\tevent.preventDefault();\n\t\t\t});\n\t\t}\n\t},\n\n\t_createIcons: function() {\n\t\tvar options = this.options;\n\t\tif ( options.icons ) {\n\t\t\t$( \"<span></span>\" )\n\t\t\t\t.addClass( \"ui-icon \" + options.icons.header )\n\t\t\t\t.prependTo( this.headers );\n\t\t\tthis.active.children( \".ui-icon\" )\n\t\t\t\t.toggleClass(options.icons.header)\n\t\t\t\t.toggleClass(options.icons.headerSelected);\n\t\t\tthis.element.addClass( \"ui-accordion-icons\" );\n\t\t}\n\t},\n\n\t_destroyIcons: function() {\n\t\tthis.headers.children( \".ui-icon\" ).remove();\n\t\tthis.element.removeClass( \"ui-accordion-icons\" );\n\t},\n\n\tdestroy: function() {\n\t\tvar options = this.options;\n\n\t\tthis.element\n\t\t\t.removeClass( \"ui-accordion ui-widget ui-helper-reset\" )\n\t\t\t.removeAttr( \"role\" );\n\n\t\tthis.headers\n\t\t\t.unbind( \".accordion\" )\n\t\t\t.removeClass( \"ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-expanded\" )\n\t\t\t.removeAttr( \"tabIndex\" );\n\n\t\tthis.headers.find( \"a\" ).removeAttr( \"tabIndex\" );\n\t\tthis._destroyIcons();\n\t\tvar contents = this.headers.next()\n\t\t\t.css( \"display\", \"\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeClass( \"ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled\" );\n\t\tif ( options.autoHeight || options.fillHeight ) {\n\t\t\tcontents.css( \"height\", \"\" );\n\t\t}\n\n\t\treturn $.Widget.prototype.destroy.call( this );\n\t},\n\n\t_setOption: function( key, value ) {\n\t\t$.Widget.prototype._setOption.apply( this, arguments );\n\t\t\t\n\t\tif ( key == \"active\" ) {\n\t\t\tthis.activate( value );\n\t\t}\n\t\tif ( key == \"icons\" ) {\n\t\t\tthis._destroyIcons();\n\t\t\tif ( value ) {\n\t\t\t\tthis._createIcons();\n\t\t\t}\n\t\t}\n\t\t// #5332 - opacity doesn't cascade to positioned elements in IE\n\t\t// so we need to add the disabled class to the headers and panels\n\t\tif ( key == \"disabled\" ) {\n\t\t\tthis.headers.add(this.headers.next())\n\t\t\t\t[ value ? \"addClass\" : \"removeClass\" ](\n\t\t\t\t\t\"ui-accordion-disabled ui-state-disabled\" );\n\t\t}\n\t},\n\n\t_keydown: function( event ) {\n\t\tif ( this.options.disabled || event.altKey || event.ctrlKey ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar keyCode = $.ui.keyCode,\n\t\t\tlength = this.headers.length,\n\t\t\tcurrentIndex = this.headers.index( event.target ),\n\t\t\ttoFocus = false;\n\n\t\tswitch ( event.keyCode ) {\n\t\t\tcase keyCode.RIGHT:\n\t\t\tcase keyCode.DOWN:\n\t\t\t\ttoFocus = this.headers[ ( currentIndex + 1 ) % length ];\n\t\t\t\tbreak;\n\t\t\tcase keyCode.LEFT:\n\t\t\tcase keyCode.UP:\n\t\t\t\ttoFocus = this.headers[ ( currentIndex - 1 + length ) % length ];\n\t\t\t\tbreak;\n\t\t\tcase keyCode.SPACE:\n\t\t\tcase keyCode.ENTER:\n\t\t\t\tthis._clickHandler( { target: event.target }, event.target );\n\t\t\t\tevent.preventDefault();\n\t\t}\n\n\t\tif ( toFocus ) {\n\t\t\t$( event.target ).attr( \"tabIndex\", -1 );\n\t\t\t$( toFocus ).attr( \"tabIndex\", 0 );\n\t\t\ttoFocus.focus();\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t},\n\n\tresize: function() {\n\t\tvar options = this.options,\n\t\t\tmaxHeight;\n\n\t\tif ( options.fillSpace ) {\n\t\t\tif ( $.browser.msie ) {\n\t\t\t\tvar defOverflow = this.element.parent().css( \"overflow\" );\n\t\t\t\tthis.element.parent().css( \"overflow\", \"hidden\");\n\t\t\t}\n\t\t\tmaxHeight = this.element.parent().height();\n\t\t\tif ($.browser.msie) {\n\t\t\t\tthis.element.parent().css( \"overflow\", defOverflow );\n\t\t\t}\n\n\t\t\tthis.headers.each(function() {\n\t\t\t\tmaxHeight -= $( this ).outerHeight( true );\n\t\t\t});\n\n\t\t\tthis.headers.next()\n\t\t\t\t.each(function() {\n\t\t\t\t\t$( this ).height( Math.max( 0, maxHeight -\n\t\t\t\t\t\t$( this ).innerHeight() + $( this ).height() ) );\n\t\t\t\t})\n\t\t\t\t.css( \"overflow\", \"auto\" );\n\t\t} else if ( options.autoHeight ) {\n\t\t\tmaxHeight = 0;\n\t\t\tthis.headers.next()\n\t\t\t\t.each(function() {\n\t\t\t\t\tmaxHeight = Math.max( maxHeight, $( this ).height( \"\" ).height() );\n\t\t\t\t})\n\t\t\t\t.height( maxHeight );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tactivate: function( index ) {\n\t\t// TODO this gets called on init, changing the option without an explicit call for that\n\t\tthis.options.active = index;\n\t\t// call clickHandler with custom event\n\t\tvar active = this._findActive( index )[ 0 ];\n\t\tthis._clickHandler( { target: active }, active );\n\n\t\treturn this;\n\t},\n\n\t_findActive: function( selector ) {\n\t\treturn selector\n\t\t\t? typeof selector === \"number\"\n\t\t\t\t? this.headers.filter( \":eq(\" + selector + \")\" )\n\t\t\t\t: this.headers.not( this.headers.not( selector ) )\n\t\t\t: selector === false\n\t\t\t\t? $( [] )\n\t\t\t\t: this.headers.filter( \":eq(0)\" );\n\t},\n\n\t// TODO isn't event.target enough? why the separate target argument?\n\t_clickHandler: function( event, target ) {\n\t\tvar options = this.options;\n\t\tif ( options.disabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// called only when using activate(false) to close all parts programmatically\n\t\tif ( !event.target ) {\n\t\t\tif ( !options.collapsible ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.active\n\t\t\t\t.removeClass( \"ui-state-active ui-corner-top\" )\n\t\t\t\t.addClass( \"ui-state-default ui-corner-all\" )\n\t\t\t\t.children( \".ui-icon\" )\n\t\t\t\t\t.removeClass( options.icons.headerSelected )\n\t\t\t\t\t.addClass( options.icons.header );\n\t\t\tthis.active.next().addClass( \"ui-accordion-content-active\" );\n\t\t\tvar toHide = this.active.next(),\n\t\t\t\tdata = {\n\t\t\t\t\toptions: options,\n\t\t\t\t\tnewHeader: $( [] ),\n\t\t\t\t\toldHeader: options.active,\n\t\t\t\t\tnewContent: $( [] ),\n\t\t\t\t\toldContent: toHide\n\t\t\t\t},\n\t\t\t\ttoShow = ( this.active = $( [] ) );\n\t\t\tthis._toggle( toShow, toHide, data );\n\t\t\treturn;\n\t\t}\n\n\t\t// get the click target\n\t\tvar clicked = $( event.currentTarget || target ),\n\t\t\tclickedIsActive = clicked[0] === this.active[0];\n\n\t\t// TODO the option is changed, is that correct?\n\t\t// TODO if it is correct, shouldn't that happen after determining that the click is valid?\n\t\toptions.active = options.collapsible && clickedIsActive ?\n\t\t\tfalse :\n\t\t\tthis.headers.index( clicked );\n\n\t\t// if animations are still active, or the active header is the target, ignore click\n\t\tif ( this.running || ( !options.collapsible && clickedIsActive ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// switch classes\n\t\tthis.active\n\t\t\t.removeClass( \"ui-state-active ui-corner-top\" )\n\t\t\t.addClass( \"ui-state-default ui-corner-all\" )\n\t\t\t.children( \".ui-icon\" )\n\t\t\t\t.removeClass( options.icons.headerSelected )\n\t\t\t\t.addClass( options.icons.header );\n\t\tif ( !clickedIsActive ) {\n\t\t\tclicked\n\t\t\t\t.removeClass( \"ui-state-default ui-corner-all\" )\n\t\t\t\t.addClass( \"ui-state-active ui-corner-top\" )\n\t\t\t\t.children( \".ui-icon\" )\n\t\t\t\t\t.removeClass( options.icons.header )\n\t\t\t\t\t.addClass( options.icons.headerSelected );\n\t\t\tclicked\n\t\t\t\t.next()\n\t\t\t\t.addClass( \"ui-accordion-content-active\" );\n\t\t}\n\n\t\t// find elements to show and hide\n\t\tvar toShow = clicked.next(),\n\t\t\ttoHide = this.active.next(),\n\t\t\tdata = {\n\t\t\t\toptions: options,\n\t\t\t\tnewHeader: clickedIsActive && options.collapsible ? $([]) : clicked,\n\t\t\t\toldHeader: this.active,\n\t\t\t\tnewContent: clickedIsActive && options.collapsible ? $([]) : toShow,\n\t\t\t\toldContent: toHide\n\t\t\t},\n\t\t\tdown = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );\n\n\t\tthis.active = clickedIsActive ? $([]) : clicked;\n\t\tthis._toggle( toShow, toHide, data, clickedIsActive, down );\n\n\t\treturn;\n\t},\n\n\t_toggle: function( toShow, toHide, data, clickedIsActive, down ) {\n\t\tvar self = this,\n\t\t\toptions = self.options;\n\n\t\tself.toShow = toShow;\n\t\tself.toHide = toHide;\n\t\tself.data = data;\n\n\t\tvar complete = function() {\n\t\t\tif ( !self ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn self._completed.apply( self, arguments );\n\t\t};\n\n\t\t// trigger changestart event\n\t\tself._trigger( \"changestart\", null, self.data );\n\n\t\t// count elements to animate\n\t\tself.running = toHide.size() === 0 ? toShow.size() : toHide.size();\n\n\t\tif ( options.animated ) {\n\t\t\tvar animOptions = {};\n\n\t\t\tif ( options.collapsible && clickedIsActive ) {\n\t\t\t\tanimOptions = {\n\t\t\t\t\ttoShow: $( [] ),\n\t\t\t\t\ttoHide: toHide,\n\t\t\t\t\tcomplete: complete,\n\t\t\t\t\tdown: down,\n\t\t\t\t\tautoHeight: options.autoHeight || options.fillSpace\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tanimOptions = {\n\t\t\t\t\ttoShow: toShow,\n\t\t\t\t\ttoHide: toHide,\n\t\t\t\t\tcomplete: complete,\n\t\t\t\t\tdown: down,\n\t\t\t\t\tautoHeight: options.autoHeight || options.fillSpace\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif ( !options.proxied ) {\n\t\t\t\toptions.proxied = options.animated;\n\t\t\t}\n\n\t\t\tif ( !options.proxiedDuration ) {\n\t\t\t\toptions.proxiedDuration = options.duration;\n\t\t\t}\n\n\t\t\toptions.animated = $.isFunction( options.proxied ) ?\n\t\t\t\toptions.proxied( animOptions ) :\n\t\t\t\toptions.proxied;\n\n\t\t\toptions.duration = $.isFunction( options.proxiedDuration ) ?\n\t\t\t\toptions.proxiedDuration( animOptions ) :\n\t\t\t\toptions.proxiedDuration;\n\n\t\t\tvar animations = $.ui.accordion.animations,\n\t\t\t\tduration = options.duration,\n\t\t\t\teasing = options.animated;\n\n\t\t\tif ( easing && !animations[ easing ] && !$.easing[ easing ] ) {\n\t\t\t\teasing = \"slide\";\n\t\t\t}\n\t\t\tif ( !animations[ easing ] ) {\n\t\t\t\tanimations[ easing ] = function( options ) {\n\t\t\t\t\tthis.slide( options, {\n\t\t\t\t\t\teasing: easing,\n\t\t\t\t\t\tduration: duration || 700\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tanimations[ easing ]( animOptions );\n\t\t} else {\n\t\t\tif ( options.collapsible && clickedIsActive ) {\n\t\t\t\ttoShow.toggle();\n\t\t\t} else {\n\t\t\t\ttoHide.hide();\n\t\t\t\ttoShow.show();\n\t\t\t}\n\n\t\t\tcomplete( true );\n\t\t}\n\n\t\t// TODO assert that the blur and focus triggers are really necessary, remove otherwise\n\t\ttoHide.prev()\n\t\t\t.attr({\n\t\t\t\t\"aria-expanded\": \"false\",\n\t\t\t\ttabIndex: -1\n\t\t\t})\n\t\t\t.blur();\n\t\ttoShow.prev()\n\t\t\t.attr({\n\t\t\t\t\"aria-expanded\": \"true\",\n\t\t\t\ttabIndex: 0\n\t\t\t})\n\t\t\t.focus();\n\t},\n\n\t_completed: function( cancel ) {\n\t\tthis.running = cancel ? 0 : --this.running;\n\t\tif ( this.running ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.options.clearStyle ) {\n\t\t\tthis.toShow.add( this.toHide ).css({\n\t\t\t\theight: \"\",\n\t\t\t\toverflow: \"\"\n\t\t\t});\n\t\t}\n\n\t\t// other classes are removed before the animation; this one needs to stay until completed\n\t\tthis.toHide.removeClass( \"ui-accordion-content-active\" );\n\n\t\tthis._trigger( \"change\", null, this.data );\n\t}\n});\n\n$.extend( $.ui.accordion, {\n\tversion: \"1.8.6\",\n\tanimations: {\n\t\tslide: function( options, additions ) {\n\t\t\toptions = $.extend({\n\t\t\t\teasing: \"swing\",\n\t\t\t\tduration: 300\n\t\t\t}, options, additions );\n\t\t\tif ( !options.toHide.size() ) {\n\t\t\t\toptions.toShow.animate({\n\t\t\t\t\theight: \"show\",\n\t\t\t\t\tpaddingTop: \"show\",\n\t\t\t\t\tpaddingBottom: \"show\"\n\t\t\t\t}, options );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( !options.toShow.size() ) {\n\t\t\t\toptions.toHide.animate({\n\t\t\t\t\theight: \"hide\",\n\t\t\t\t\tpaddingTop: \"hide\",\n\t\t\t\t\tpaddingBottom: \"hide\"\n\t\t\t\t}, options );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar overflow = options.toShow.css( \"overflow\" ),\n\t\t\t\tpercentDone = 0,\n\t\t\t\tshowProps = {},\n\t\t\t\thideProps = {},\n\t\t\t\tfxAttrs = [ \"height\", \"paddingTop\", \"paddingBottom\" ],\n\t\t\t\toriginalWidth;\n\t\t\t// fix width before calculating height of hidden element\n\t\t\tvar s = options.toShow;\n\t\t\toriginalWidth = s[0].style.width;\n\t\t\ts.width( parseInt( s.parent().width(), 10 )\n\t\t\t\t- parseInt( s.css( \"paddingLeft\" ), 10 )\n\t\t\t\t- parseInt( s.css( \"paddingRight\" ), 10 )\n\t\t\t\t- ( parseInt( s.css( \"borderLeftWidth\" ), 10 ) || 0 )\n\t\t\t\t- ( parseInt( s.css( \"borderRightWidth\" ), 10) || 0 ) );\n\n\t\t\t$.each( fxAttrs, function( i, prop ) {\n\t\t\t\thideProps[ prop ] = \"hide\";\n\n\t\t\t\tvar parts = ( \"\" + $.css( options.toShow[0], prop ) ).match( /^([\\d+-.]+)(.*)$/ );\n\t\t\t\tshowProps[ prop ] = {\n\t\t\t\t\tvalue: parts[ 1 ],\n\t\t\t\t\tunit: parts[ 2 ] || \"px\"\n\t\t\t\t};\n\t\t\t});\n\t\t\toptions.toShow.css({ height: 0, overflow: \"hidden\" }).show();\n\t\t\toptions.toHide\n\t\t\t\t.filter( \":hidden\" )\n\t\t\t\t\t.each( options.complete )\n\t\t\t\t.end()\n\t\t\t\t.filter( \":visible\" )\n\t\t\t\t.animate( hideProps, {\n\t\t\t\tstep: function( now, settings ) {\n\t\t\t\t\t// only calculate the percent when animating height\n\t\t\t\t\t// IE gets very inconsistent results when animating elements\n\t\t\t\t\t// with small values, which is common for padding\n\t\t\t\t\tif ( settings.prop == \"height\" ) {\n\t\t\t\t\t\tpercentDone = ( settings.end - settings.start === 0 ) ? 0 :\n\t\t\t\t\t\t\t( settings.now - settings.start ) / ( settings.end - settings.start );\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.toShow[ 0 ].style[ settings.prop ] =\n\t\t\t\t\t\t( percentDone * showProps[ settings.prop ].value )\n\t\t\t\t\t\t+ showProps[ settings.prop ].unit;\n\t\t\t\t},\n\t\t\t\tduration: options.duration,\n\t\t\t\teasing: options.easing,\n\t\t\t\tcomplete: function() {\n\t\t\t\t\tif ( !options.autoHeight ) {\n\t\t\t\t\t\toptions.toShow.css( \"height\", \"\" );\n\t\t\t\t\t}\n\t\t\t\t\toptions.toShow.css({\n\t\t\t\t\t\twidth: originalWidth,\n\t\t\t\t\t\toverflow: overflow\n\t\t\t\t\t});\n\t\t\t\t\toptions.complete();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tbounceslide: function( options ) {\n\t\t\tthis.slide( options, {\n\t\t\t\teasing: options.down ? \"easeOutBounce\" : \"swing\",\n\t\t\t\tduration: options.down ? 1000 : 200\n\t\t\t});\n\t\t}\n\t}\n});\n\n})( jQuery );\n/*\n * jQuery UI Autocomplete 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Autocomplete\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.widget.js\n *\tjquery.ui.position.js\n */\n(function( $, undefined ) {\n\n$.widget( \"ui.autocomplete\", {\n\toptions: {\n\t\tappendTo: \"body\",\n\t\tdelay: 300,\n\t\tminLength: 1,\n\t\tposition: {\n\t\t\tmy: \"left top\",\n\t\t\tat: \"left bottom\",\n\t\t\tcollision: \"none\"\n\t\t},\n\t\tsource: null\n\t},\n\t_create: function() {\n\t\tvar self = this,\n\t\t\tdoc = this.element[ 0 ].ownerDocument,\n\t\t\tsuppressKeyPress;\n\n\t\tthis.element\n\t\t\t.addClass( \"ui-autocomplete-input\" )\n\t\t\t.attr( \"autocomplete\", \"off\" )\n\t\t\t// TODO verify these actually work as intended\n\t\t\t.attr({\n\t\t\t\trole: \"textbox\",\n\t\t\t\t\"aria-autocomplete\": \"list\",\n\t\t\t\t\"aria-haspopup\": \"true\"\n\t\t\t})\n\t\t\t.bind( \"keydown.autocomplete\", function( event ) {\n\t\t\t\tif ( self.options.disabled || self.element.attr( \"readonly\" ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tsuppressKeyPress = false;\n\t\t\t\tvar keyCode = $.ui.keyCode;\n\t\t\t\tswitch( event.keyCode ) {\n\t\t\t\tcase keyCode.PAGE_UP:\n\t\t\t\t\tself._move( \"previousPage\", event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.PAGE_DOWN:\n\t\t\t\t\tself._move( \"nextPage\", event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.UP:\n\t\t\t\t\tself._move( \"previous\", event );\n\t\t\t\t\t// prevent moving cursor to beginning of text field in some browsers\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.DOWN:\n\t\t\t\t\tself._move( \"next\", event );\n\t\t\t\t\t// prevent moving cursor to end of text field in some browsers\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.ENTER:\n\t\t\t\tcase keyCode.NUMPAD_ENTER:\n\t\t\t\t\t// when menu is open and has focus\n\t\t\t\t\tif ( self.menu.active ) {\n\t\t\t\t\t\t// #6055 - Opera still allows the keypress to occur\n\t\t\t\t\t\t// which causes forms to submit\n\t\t\t\t\t\tsuppressKeyPress = true;\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t\t//passthrough - ENTER and TAB both select the current element\n\t\t\t\tcase keyCode.TAB:\n\t\t\t\t\tif ( !self.menu.active ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tself.menu.select( event );\n\t\t\t\t\tbreak;\n\t\t\t\tcase keyCode.ESCAPE:\n\t\t\t\t\tself.element.val( self.term );\n\t\t\t\t\tself.close( event );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t// keypress is triggered before the input value is changed\n\t\t\t\t\tclearTimeout( self.searching );\n\t\t\t\t\tself.searching = setTimeout(function() {\n\t\t\t\t\t\t// only search if the value has changed\n\t\t\t\t\t\tif ( self.term != self.element.val() ) {\n\t\t\t\t\t\t\tself.selectedItem = null;\n\t\t\t\t\t\t\tself.search( null, event );\n\t\t\t\t\t\t}\n\t\t\t\t\t}, self.options.delay );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.bind( \"keypress.autocomplete\", function( event ) {\n\t\t\t\tif ( suppressKeyPress ) {\n\t\t\t\t\tsuppressKeyPress = false;\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t})\n\t\t\t.bind( \"focus.autocomplete\", function() {\n\t\t\t\tif ( self.options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tself.selectedItem = null;\n\t\t\t\tself.previous = self.element.val();\n\t\t\t})\n\t\t\t.bind( \"blur.autocomplete\", function( event ) {\n\t\t\t\tif ( self.options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tclearTimeout( self.searching );\n\t\t\t\t// clicks on the menu (or a button to trigger a search) will cause a blur event\n\t\t\t\tself.closing = setTimeout(function() {\n\t\t\t\t\tself.close( event );\n\t\t\t\t\tself._change( event );\n\t\t\t\t}, 150 );\n\t\t\t});\n\t\tthis._initSource();\n\t\tthis.response = function() {\n\t\t\treturn self._response.apply( self, arguments );\n\t\t};\n\t\tthis.menu = $( \"<ul></ul>\" )\n\t\t\t.addClass( \"ui-autocomplete\" )\n\t\t\t.appendTo( $( this.options.appendTo || \"body\", doc )[0] )\n\t\t\t// prevent the close-on-blur in case of a \"slow\" click on the menu (long mousedown)\n\t\t\t.mousedown(function( event ) {\n\t\t\t\t// clicking on the scrollbar causes focus to shift to the body\n\t\t\t\t// but we can't detect a mouseup or a click immediately afterward\n\t\t\t\t// so we have to track the next mousedown and close the menu if\n\t\t\t\t// the user clicks somewhere outside of the autocomplete\n\t\t\t\tvar menuElement = self.menu.element[ 0 ];\n\t\t\t\tif ( !$( event.target ).closest( \".ui-menu-item\" ).length ) {\n\t\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t\t$( document ).one( 'mousedown', function( event ) {\n\t\t\t\t\t\t\tif ( event.target !== self.element[ 0 ] &&\n\t\t\t\t\t\t\t\tevent.target !== menuElement &&\n\t\t\t\t\t\t\t\t!$.ui.contains( menuElement, event.target ) ) {\n\t\t\t\t\t\t\t\tself.close();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}, 1 );\n\t\t\t\t}\n\n\t\t\t\t// use another timeout to make sure the blur-event-handler on the input was already triggered\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tclearTimeout( self.closing );\n\t\t\t\t}, 13);\n\t\t\t})\n\t\t\t.menu({\n\t\t\t\tfocus: function( event, ui ) {\n\t\t\t\t\tvar item = ui.item.data( \"item.autocomplete\" );\n\t\t\t\t\tif ( false !== self._trigger( \"focus\", event, { item: item } ) ) {\n\t\t\t\t\t\t// use value to match what will end up in the input, if it was a key event\n\t\t\t\t\t\tif ( /^key/.test(event.originalEvent.type) ) {\n\t\t\t\t\t\t\tself.element.val( item.value );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tselected: function( event, ui ) {\n\t\t\t\t\tvar item = ui.item.data( \"item.autocomplete\" ),\n\t\t\t\t\t\tprevious = self.previous;\n\n\t\t\t\t\t// only trigger when focus was lost (click on menu)\n\t\t\t\t\tif ( self.element[0] !== doc.activeElement ) {\n\t\t\t\t\t\tself.element.focus();\n\t\t\t\t\t\tself.previous = previous;\n\t\t\t\t\t\t// #6109 - IE triggers two focus events and the second\n\t\t\t\t\t\t// is asynchronous, so we need to reset the previous\n\t\t\t\t\t\t// term synchronously and asynchronously :-(\n\t\t\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t\t\tself.previous = previous;\n\t\t\t\t\t\t}, 1);\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( false !== self._trigger( \"select\", event, { item: item } ) ) {\n\t\t\t\t\t\tself.element.val( item.value );\n\t\t\t\t\t}\n\t\t\t\t\t// reset the term after the select event\n\t\t\t\t\t// this allows custom select handling to work properly\n\t\t\t\t\tself.term = self.element.val();\n\n\t\t\t\t\tself.close( event );\n\t\t\t\t\tself.selectedItem = item;\n\t\t\t\t},\n\t\t\t\tblur: function( event, ui ) {\n\t\t\t\t\t// don't set the value of the text field if it's already correct\n\t\t\t\t\t// this prevents moving the cursor unnecessarily\n\t\t\t\t\tif ( self.menu.element.is(\":visible\") &&\n\t\t\t\t\t\t( self.element.val() !== self.term ) ) {\n\t\t\t\t\t\tself.element.val( self.term );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.zIndex( this.element.zIndex() + 1 )\n\t\t\t// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781\n\t\t\t.css({ top: 0, left: 0 })\n\t\t\t.hide()\n\t\t\t.data( \"menu\" );\n\t\tif ( $.fn.bgiframe ) {\n\t\t\t this.menu.element.bgiframe();\n\t\t}\n\t},\n\n\tdestroy: function() {\n\t\tthis.element\n\t\t\t.removeClass( \"ui-autocomplete-input\" )\n\t\t\t.removeAttr( \"autocomplete\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-autocomplete\" )\n\t\t\t.removeAttr( \"aria-haspopup\" );\n\t\tthis.menu.element.remove();\n\t\t$.Widget.prototype.destroy.call( this );\n\t},\n\n\t_setOption: function( key, value ) {\n\t\t$.Widget.prototype._setOption.apply( this, arguments );\n\t\tif ( key === \"source\" ) {\n\t\t\tthis._initSource();\n\t\t}\n\t\tif ( key === \"appendTo\" ) {\n\t\t\tthis.menu.element.appendTo( $( value || \"body\", this.element[0].ownerDocument )[0] )\n\t\t}\n\t},\n\n\t_initSource: function() {\n\t\tvar self = this,\n\t\t\tarray,\n\t\t\turl;\n\t\tif ( $.isArray(this.options.source) ) {\n\t\t\tarray = this.options.source;\n\t\t\tthis.source = function( request, response ) {\n\t\t\t\tresponse( $.ui.autocomplete.filter(array, request.term) );\n\t\t\t};\n\t\t} else if ( typeof this.options.source === \"string\" ) {\n\t\t\turl = this.options.source;\n\t\t\tthis.source = function( request, response ) {\n\t\t\t\tif (self.xhr) {\n\t\t\t\t\tself.xhr.abort();\n\t\t\t\t}\n\t\t\t\tself.xhr = $.getJSON( url, request, function( data, status, xhr ) {\n\t\t\t\t\tif ( xhr === self.xhr ) {\n\t\t\t\t\t\tresponse( data );\n\t\t\t\t\t}\n\t\t\t\t\tself.xhr = null;\n\t\t\t\t});\n\t\t\t};\n\t\t} else {\n\t\t\tthis.source = this.options.source;\n\t\t}\n\t},\n\n\tsearch: function( value, event ) {\n\t\tvalue = value != null ? value : this.element.val();\n\n\t\t// always save the actual value, not the one passed as an argument\n\t\tthis.term = this.element.val();\n\n\t\tif ( value.length < this.options.minLength ) {\n\t\t\treturn this.close( event );\n\t\t}\n\n\t\tclearTimeout( this.closing );\n\t\tif ( this._trigger( \"search\", event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn this._search( value );\n\t},\n\n\t_search: function( value ) {\n\t\tthis.element.addClass( \"ui-autocomplete-loading\" );\n\n\t\tthis.source( { term: value }, this.response );\n\t},\n\n\t_response: function( content ) {\n\t\tif ( content && content.length ) {\n\t\t\tcontent = this._normalize( content );\n\t\t\tthis._suggest( content );\n\t\t\tthis._trigger( \"open\" );\n\t\t} else {\n\t\t\tthis.close();\n\t\t}\n\t\tthis.element.removeClass( \"ui-autocomplete-loading\" );\n\t},\n\n\tclose: function( event ) {\n\t\tclearTimeout( this.closing );\n\t\tif ( this.menu.element.is(\":visible\") ) {\n\t\t\tthis._trigger( \"close\", event );\n\t\t\tthis.menu.element.hide();\n\t\t\tthis.menu.deactivate();\n\t\t}\n\t},\n\t\n\t_change: function( event ) {\n\t\tif ( this.previous !== this.element.val() ) {\n\t\t\tthis._trigger( \"change\", event, { item: this.selectedItem } );\n\t\t}\n\t},\n\n\t_normalize: function( items ) {\n\t\t// assume all items have the right format when the first item is complete\n\t\tif ( items.length && items[0].label && items[0].value ) {\n\t\t\treturn items;\n\t\t}\n\t\treturn $.map( items, function(item) {\n\t\t\tif ( typeof item === \"string\" ) {\n\t\t\t\treturn {\n\t\t\t\t\tlabel: item,\n\t\t\t\t\tvalue: item\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn $.extend({\n\t\t\t\tlabel: item.label || item.value,\n\t\t\t\tvalue: item.value || item.label\n\t\t\t}, item );\n\t\t});\n\t},\n\n\t_suggest: function( items ) {\n\t\tvar ul = this.menu.element\n\t\t\t.empty()\n\t\t\t.zIndex( this.element.zIndex() + 1 );\n\t\tthis._renderMenu( ul, items );\n\t\t// TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate\n\t\tthis.menu.deactivate();\n\t\tthis.menu.refresh();\n\t\tthis.menu.element.show().position( $.extend({\n\t\t\tof: this.element\n\t\t}, this.options.position ));\n\n\t\tthis._resizeMenu();\n\t},\n\n\t_resizeMenu: function() {\n\t\tvar ul = this.menu.element;\n\t\tul.outerWidth( Math.max(\n\t\t\tul.width( \"\" ).outerWidth(),\n\t\t\tthis.element.outerWidth()\n\t\t) );\n\t},\n\n\t_renderMenu: function( ul, items ) {\n\t\tvar self = this;\n\t\t$.each( items, function( index, item ) {\n\t\t\tself._renderItem( ul, item );\n\t\t});\n\t},\n\n\t_renderItem: function( ul, item) {\n\t\treturn $( \"<li></li>\" )\n\t\t\t.data( \"item.autocomplete\", item )\n\t\t\t.append( $( \"<a></a>\" ).text( item.label ) )\n\t\t\t.appendTo( ul );\n\t},\n\n\t_move: function( direction, event ) {\n\t\tif ( !this.menu.element.is(\":visible\") ) {\n\t\t\tthis.search( null, event );\n\t\t\treturn;\n\t\t}\n\t\tif ( this.menu.first() && /^previous/.test(direction) ||\n\t\t\t\tthis.menu.last() && /^next/.test(direction) ) {\n\t\t\tthis.element.val( this.term );\n\t\t\tthis.menu.deactivate();\n\t\t\treturn;\n\t\t}\n\t\tthis.menu[ direction ]( event );\n\t},\n\n\twidget: function() {\n\t\treturn this.menu.element;\n\t}\n});\n\n$.extend( $.ui.autocomplete, {\n\tescapeRegex: function( value ) {\n\t\treturn value.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, \"\\\\$&\");\n\t},\n\tfilter: function(array, term) {\n\t\tvar matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), \"i\" );\n\t\treturn $.grep( array, function(value) {\n\t\t\treturn matcher.test( value.label || value.value || value );\n\t\t});\n\t}\n});\n\n}( jQuery ));\n\n/*\n * jQuery UI Menu (not officially released)\n * \n * This widget isn't yet finished and the API is subject to change. We plan to finish\n * it for the next release. You're welcome to give it a try anyway and give us feedback,\n * as long as you're okay with migrating your code later on. We can help with that, too.\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Menu\n *\n * Depends:\n *\tjquery.ui.core.js\n *  jquery.ui.widget.js\n */\n(function($) {\n\n$.widget(\"ui.menu\", {\n\t_create: function() {\n\t\tvar self = this;\n\t\tthis.element\n\t\t\t.addClass(\"ui-menu ui-widget ui-widget-content ui-corner-all\")\n\t\t\t.attr({\n\t\t\t\trole: \"listbox\",\n\t\t\t\t\"aria-activedescendant\": \"ui-active-menuitem\"\n\t\t\t})\n\t\t\t.click(function( event ) {\n\t\t\t\tif ( !$( event.target ).closest( \".ui-menu-item a\" ).length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// temporary\n\t\t\t\tevent.preventDefault();\n\t\t\t\tself.select( event );\n\t\t\t});\n\t\tthis.refresh();\n\t},\n\t\n\trefresh: function() {\n\t\tvar self = this;\n\n\t\t// don't refresh list items that are already adapted\n\t\tvar items = this.element.children(\"li:not(.ui-menu-item):has(a)\")\n\t\t\t.addClass(\"ui-menu-item\")\n\t\t\t.attr(\"role\", \"menuitem\");\n\t\t\n\t\titems.children(\"a\")\n\t\t\t.addClass(\"ui-corner-all\")\n\t\t\t.attr(\"tabindex\", -1)\n\t\t\t// mouseenter doesn't work with event delegation\n\t\t\t.mouseenter(function( event ) {\n\t\t\t\tself.activate( event, $(this).parent() );\n\t\t\t})\n\t\t\t.mouseleave(function() {\n\t\t\t\tself.deactivate();\n\t\t\t});\n\t},\n\n\tactivate: function( event, item ) {\n\t\tthis.deactivate();\n\t\tif (this.hasScroll()) {\n\t\t\tvar offset = item.offset().top - this.element.offset().top,\n\t\t\t\tscroll = this.element.attr(\"scrollTop\"),\n\t\t\t\telementHeight = this.element.height();\n\t\t\tif (offset < 0) {\n\t\t\t\tthis.element.attr(\"scrollTop\", scroll + offset);\n\t\t\t} else if (offset >= elementHeight) {\n\t\t\t\tthis.element.attr(\"scrollTop\", scroll + offset - elementHeight + item.height());\n\t\t\t}\n\t\t}\n\t\tthis.active = item.eq(0)\n\t\t\t.children(\"a\")\n\t\t\t\t.addClass(\"ui-state-hover\")\n\t\t\t\t.attr(\"id\", \"ui-active-menuitem\")\n\t\t\t.end();\n\t\tthis._trigger(\"focus\", event, { item: item });\n\t},\n\n\tdeactivate: function() {\n\t\tif (!this.active) { return; }\n\n\t\tthis.active.children(\"a\")\n\t\t\t.removeClass(\"ui-state-hover\")\n\t\t\t.removeAttr(\"id\");\n\t\tthis._trigger(\"blur\");\n\t\tthis.active = null;\n\t},\n\n\tnext: function(event) {\n\t\tthis.move(\"next\", \".ui-menu-item:first\", event);\n\t},\n\n\tprevious: function(event) {\n\t\tthis.move(\"prev\", \".ui-menu-item:last\", event);\n\t},\n\n\tfirst: function() {\n\t\treturn this.active && !this.active.prevAll(\".ui-menu-item\").length;\n\t},\n\n\tlast: function() {\n\t\treturn this.active && !this.active.nextAll(\".ui-menu-item\").length;\n\t},\n\n\tmove: function(direction, edge, event) {\n\t\tif (!this.active) {\n\t\t\tthis.activate(event, this.element.children(edge));\n\t\t\treturn;\n\t\t}\n\t\tvar next = this.active[direction + \"All\"](\".ui-menu-item\").eq(0);\n\t\tif (next.length) {\n\t\t\tthis.activate(event, next);\n\t\t} else {\n\t\t\tthis.activate(event, this.element.children(edge));\n\t\t}\n\t},\n\n\t// TODO merge with previousPage\n\tnextPage: function(event) {\n\t\tif (this.hasScroll()) {\n\t\t\t// TODO merge with no-scroll-else\n\t\t\tif (!this.active || this.last()) {\n\t\t\t\tthis.activate(event, this.element.children(\".ui-menu-item:first\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar base = this.active.offset().top,\n\t\t\t\theight = this.element.height(),\n\t\t\t\tresult = this.element.children(\".ui-menu-item\").filter(function() {\n\t\t\t\t\tvar close = $(this).offset().top - base - height + $(this).height();\n\t\t\t\t\t// TODO improve approximation\n\t\t\t\t\treturn close < 10 && close > -10;\n\t\t\t\t});\n\n\t\t\t// TODO try to catch this earlier when scrollTop indicates the last page anyway\n\t\t\tif (!result.length) {\n\t\t\t\tresult = this.element.children(\".ui-menu-item:last\");\n\t\t\t}\n\t\t\tthis.activate(event, result);\n\t\t} else {\n\t\t\tthis.activate(event, this.element.children(\".ui-menu-item\")\n\t\t\t\t.filter(!this.active || this.last() ? \":first\" : \":last\"));\n\t\t}\n\t},\n\n\t// TODO merge with nextPage\n\tpreviousPage: function(event) {\n\t\tif (this.hasScroll()) {\n\t\t\t// TODO merge with no-scroll-else\n\t\t\tif (!this.active || this.first()) {\n\t\t\t\tthis.activate(event, this.element.children(\".ui-menu-item:last\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar base = this.active.offset().top,\n\t\t\t\theight = this.element.height();\n\t\t\t\tresult = this.element.children(\".ui-menu-item\").filter(function() {\n\t\t\t\t\tvar close = $(this).offset().top - base + height - $(this).height();\n\t\t\t\t\t// TODO improve approximation\n\t\t\t\t\treturn close < 10 && close > -10;\n\t\t\t\t});\n\n\t\t\t// TODO try to catch this earlier when scrollTop indicates the last page anyway\n\t\t\tif (!result.length) {\n\t\t\t\tresult = this.element.children(\".ui-menu-item:first\");\n\t\t\t}\n\t\t\tthis.activate(event, result);\n\t\t} else {\n\t\t\tthis.activate(event, this.element.children(\".ui-menu-item\")\n\t\t\t\t.filter(!this.active || this.first() ? \":last\" : \":first\"));\n\t\t}\n\t},\n\n\thasScroll: function() {\n\t\treturn this.element.height() < this.element.attr(\"scrollHeight\");\n\t},\n\n\tselect: function( event ) {\n\t\tthis._trigger(\"selected\", event, { item: this.active });\n\t}\n});\n\n}(jQuery));\n/*\n * jQuery UI Button 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Button\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.widget.js\n */\n(function( $, undefined ) {\n\nvar lastActive,\n\tbaseClasses = \"ui-button ui-widget ui-state-default ui-corner-all\",\n\tstateClasses = \"ui-state-hover ui-state-active \",\n\ttypeClasses = \"ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only\",\n\tformResetHandler = function( event ) {\n\t\t$( \":ui-button\", event.target.form ).each(function() {\n\t\t\tvar inst = $( this ).data( \"button\" );\n\t\t\tsetTimeout(function() {\n\t\t\t\tinst.refresh();\n\t\t\t}, 1 );\n\t\t});\n\t},\n\tradioGroup = function( radio ) {\n\t\tvar name = radio.name,\n\t\t\tform = radio.form,\n\t\t\tradios = $( [] );\n\t\tif ( name ) {\n\t\t\tif ( form ) {\n\t\t\t\tradios = $( form ).find( \"[name='\" + name + \"']\" );\n\t\t\t} else {\n\t\t\t\tradios = $( \"[name='\" + name + \"']\", radio.ownerDocument )\n\t\t\t\t\t.filter(function() {\n\t\t\t\t\t\treturn !this.form;\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn radios;\n\t};\n\n$.widget( \"ui.button\", {\n\toptions: {\n\t\tdisabled: null,\n\t\ttext: true,\n\t\tlabel: null,\n\t\ticons: {\n\t\t\tprimary: null,\n\t\t\tsecondary: null\n\t\t}\n\t},\n\t_create: function() {\n\t\tthis.element.closest( \"form\" )\n\t\t\t.unbind( \"reset.button\" )\n\t\t\t.bind( \"reset.button\", formResetHandler );\n\n\t\tif ( typeof this.options.disabled !== \"boolean\" ) {\n\t\t\tthis.options.disabled = this.element.attr( \"disabled\" );\n\t\t}\n\n\t\tthis._determineButtonType();\n\t\tthis.hasTitle = !!this.buttonElement.attr( \"title\" );\n\n\t\tvar self = this,\n\t\t\toptions = this.options,\n\t\t\ttoggleButton = this.type === \"checkbox\" || this.type === \"radio\",\n\t\t\thoverClass = \"ui-state-hover\" + ( !toggleButton ? \" ui-state-active\" : \"\" ),\n\t\t\tfocusClass = \"ui-state-focus\";\n\n\t\tif ( options.label === null ) {\n\t\t\toptions.label = this.buttonElement.html();\n\t\t}\n\n\t\tif ( this.element.is( \":disabled\" ) ) {\n\t\t\toptions.disabled = true;\n\t\t}\n\n\t\tthis.buttonElement\n\t\t\t.addClass( baseClasses )\n\t\t\t.attr( \"role\", \"button\" )\n\t\t\t.bind( \"mouseenter.button\", function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t$( this ).addClass( \"ui-state-hover\" );\n\t\t\t\tif ( this === lastActive ) {\n\t\t\t\t\t$( this ).addClass( \"ui-state-active\" );\n\t\t\t\t}\n\t\t\t})\n\t\t\t.bind( \"mouseleave.button\", function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t$( this ).removeClass( hoverClass );\n\t\t\t})\n\t\t\t.bind( \"focus.button\", function() {\n\t\t\t\t// no need to check disabled, focus won't be triggered anyway\n\t\t\t\t$( this ).addClass( focusClass );\n\t\t\t})\n\t\t\t.bind( \"blur.button\", function() {\n\t\t\t\t$( this ).removeClass( focusClass );\n\t\t\t});\n\n\t\tif ( toggleButton ) {\n\t\t\tthis.element.bind( \"change.button\", function() {\n\t\t\t\tself.refresh();\n\t\t\t});\n\t\t}\n\n\t\tif ( this.type === \"checkbox\" ) {\n\t\t\tthis.buttonElement.bind( \"click.button\", function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t$( this ).toggleClass( \"ui-state-active\" );\n\t\t\t\tself.buttonElement.attr( \"aria-pressed\", self.element[0].checked );\n\t\t\t});\n\t\t} else if ( this.type === \"radio\" ) {\n\t\t\tthis.buttonElement.bind( \"click.button\", function() {\n\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t$( this ).addClass( \"ui-state-active\" );\n\t\t\t\tself.buttonElement.attr( \"aria-pressed\", true );\n\n\t\t\t\tvar radio = self.element[ 0 ];\n\t\t\t\tradioGroup( radio )\n\t\t\t\t\t.not( radio )\n\t\t\t\t\t.map(function() {\n\t\t\t\t\t\treturn $( this ).button( \"widget\" )[ 0 ];\n\t\t\t\t\t})\n\t\t\t\t\t.removeClass( \"ui-state-active\" )\n\t\t\t\t\t.attr( \"aria-pressed\", false );\n\t\t\t});\n\t\t} else {\n\t\t\tthis.buttonElement\n\t\t\t\t.bind( \"mousedown.button\", function() {\n\t\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t$( this ).addClass( \"ui-state-active\" );\n\t\t\t\t\tlastActive = this;\n\t\t\t\t\t$( document ).one( \"mouseup\", function() {\n\t\t\t\t\t\tlastActive = null;\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t\t.bind( \"mouseup.button\", function() {\n\t\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t$( this ).removeClass( \"ui-state-active\" );\n\t\t\t\t})\n\t\t\t\t.bind( \"keydown.button\", function(event) {\n\t\t\t\t\tif ( options.disabled ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) {\n\t\t\t\t\t\t$( this ).addClass( \"ui-state-active\" );\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.bind( \"keyup.button\", function() {\n\t\t\t\t\t$( this ).removeClass( \"ui-state-active\" );\n\t\t\t\t});\n\n\t\t\tif ( this.buttonElement.is(\"a\") ) {\n\t\t\t\tthis.buttonElement.keyup(function(event) {\n\t\t\t\t\tif ( event.keyCode === $.ui.keyCode.SPACE ) {\n\t\t\t\t\t\t// TODO pass through original event correctly (just as 2nd argument doesn't work)\n\t\t\t\t\t\t$( this ).click();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// TODO: pull out $.Widget's handling for the disabled option into\n\t\t// $.Widget.prototype._setOptionDisabled so it's easy to proxy and can\n\t\t// be overridden by individual plugins\n\t\tthis._setOption( \"disabled\", options.disabled );\n\t},\n\n\t_determineButtonType: function() {\n\t\t\n\t\tif ( this.element.is(\":checkbox\") ) {\n\t\t\tthis.type = \"checkbox\";\n\t\t} else {\n\t\t\tif ( this.element.is(\":radio\") ) {\n\t\t\t\tthis.type = \"radio\";\n\t\t\t} else {\n\t\t\t\tif ( this.element.is(\"input\") ) {\n\t\t\t\t\tthis.type = \"input\";\n\t\t\t\t} else {\n\t\t\t\t\tthis.type = \"button\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif ( this.type === \"checkbox\" || this.type === \"radio\" ) {\n\t\t\t// we don't search against the document in case the element\n\t\t\t// is disconnected from the DOM\n\t\t\tthis.buttonElement = this.element.parents().last()\n\t\t\t\t.find( \"label[for=\" + this.element.attr(\"id\") + \"]\" );\n\t\t\tthis.element.addClass( \"ui-helper-hidden-accessible\" );\n\n\t\t\tvar checked = this.element.is( \":checked\" );\n\t\t\tif ( checked ) {\n\t\t\t\tthis.buttonElement.addClass( \"ui-state-active\" );\n\t\t\t}\n\t\t\tthis.buttonElement.attr( \"aria-pressed\", checked );\n\t\t} else {\n\t\t\tthis.buttonElement = this.element;\n\t\t}\n\t},\n\n\twidget: function() {\n\t\treturn this.buttonElement;\n\t},\n\n\tdestroy: function() {\n\t\tthis.element\n\t\t\t.removeClass( \"ui-helper-hidden-accessible\" );\n\t\tthis.buttonElement\n\t\t\t.removeClass( baseClasses + \" \" + stateClasses + \" \" + typeClasses )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-pressed\" )\n\t\t\t.html( this.buttonElement.find(\".ui-button-text\").html() );\n\n\t\tif ( !this.hasTitle ) {\n\t\t\tthis.buttonElement.removeAttr( \"title\" );\n\t\t}\n\n\t\t$.Widget.prototype.destroy.call( this );\n\t},\n\n\t_setOption: function( key, value ) {\n\t\t$.Widget.prototype._setOption.apply( this, arguments );\n\t\tif ( key === \"disabled\" ) {\n\t\t\tif ( value ) {\n\t\t\t\tthis.element.attr( \"disabled\", true );\n\t\t\t} else {\n\t\t\t\tthis.element.removeAttr( \"disabled\" );\n\t\t\t}\n\t\t}\n\t\tthis._resetButton();\n\t},\n\n\trefresh: function() {\n\t\tvar isDisabled = this.element.is( \":disabled\" );\n\t\tif ( isDisabled !== this.options.disabled ) {\n\t\t\tthis._setOption( \"disabled\", isDisabled );\n\t\t}\n\t\tif ( this.type === \"radio\" ) {\n\t\t\tradioGroup( this.element[0] ).each(function() {\n\t\t\t\tif ( $( this ).is( \":checked\" ) ) {\n\t\t\t\t\t$( this ).button( \"widget\" )\n\t\t\t\t\t\t.addClass( \"ui-state-active\" )\n\t\t\t\t\t\t.attr( \"aria-pressed\", true );\n\t\t\t\t} else {\n\t\t\t\t\t$( this ).button( \"widget\" )\n\t\t\t\t\t\t.removeClass( \"ui-state-active\" )\n\t\t\t\t\t\t.attr( \"aria-pressed\", false );\n\t\t\t\t}\n\t\t\t});\n\t\t} else if ( this.type === \"checkbox\" ) {\n\t\t\tif ( this.element.is( \":checked\" ) ) {\n\t\t\t\tthis.buttonElement\n\t\t\t\t\t.addClass( \"ui-state-active\" )\n\t\t\t\t\t.attr( \"aria-pressed\", true );\n\t\t\t} else {\n\t\t\t\tthis.buttonElement\n\t\t\t\t\t.removeClass( \"ui-state-active\" )\n\t\t\t\t\t.attr( \"aria-pressed\", false );\n\t\t\t}\n\t\t}\n\t},\n\n\t_resetButton: function() {\n\t\tif ( this.type === \"input\" ) {\n\t\t\tif ( this.options.label ) {\n\t\t\t\tthis.element.val( this.options.label );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tvar buttonElement = this.buttonElement.removeClass( typeClasses ),\n\t\t\tbuttonText = $( \"<span></span>\" )\n\t\t\t\t.addClass( \"ui-button-text\" )\n\t\t\t\t.html( this.options.label )\n\t\t\t\t.appendTo( buttonElement.empty() )\n\t\t\t\t.text(),\n\t\t\ticons = this.options.icons,\n\t\t\tmultipleIcons = icons.primary && icons.secondary;\n\t\tif ( icons.primary || icons.secondary ) {\n\t\t\tbuttonElement.addClass( \"ui-button-text-icon\" +\n\t\t\t\t( multipleIcons ? \"s\" : ( icons.primary ? \"-primary\" : \"-secondary\" ) ) );\n\t\t\tif ( icons.primary ) {\n\t\t\t\tbuttonElement.prepend( \"<span class='ui-button-icon-primary ui-icon \" + icons.primary + \"'></span>\" );\n\t\t\t}\n\t\t\tif ( icons.secondary ) {\n\t\t\t\tbuttonElement.append( \"<span class='ui-button-icon-secondary ui-icon \" + icons.secondary + \"'></span>\" );\n\t\t\t}\n\t\t\tif ( !this.options.text ) {\n\t\t\t\tbuttonElement\n\t\t\t\t\t.addClass( multipleIcons ? \"ui-button-icons-only\" : \"ui-button-icon-only\" )\n\t\t\t\t\t.removeClass( \"ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary\" );\n\t\t\t\tif ( !this.hasTitle ) {\n\t\t\t\t\tbuttonElement.attr( \"title\", buttonText );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tbuttonElement.addClass( \"ui-button-text-only\" );\n\t\t}\n\t}\n});\n\n$.widget( \"ui.buttonset\", {\n\t_create: function() {\n\t\tthis.element.addClass( \"ui-buttonset\" );\n\t},\n\t\n\t_init: function() {\n\t\tthis.refresh();\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key === \"disabled\" ) {\n\t\t\tthis.buttons.button( \"option\", key, value );\n\t\t}\n\n\t\t$.Widget.prototype._setOption.apply( this, arguments );\n\t},\n\t\n\trefresh: function() {\n\t\tthis.buttons = this.element.find( \":button, :submit, :reset, :checkbox, :radio, a, :data(button)\" )\n\t\t\t.filter( \":ui-button\" )\n\t\t\t\t.button( \"refresh\" )\n\t\t\t.end()\n\t\t\t.not( \":ui-button\" )\n\t\t\t\t.button()\n\t\t\t.end()\n\t\t\t.map(function() {\n\t\t\t\treturn $( this ).button( \"widget\" )[ 0 ];\n\t\t\t})\n\t\t\t\t.removeClass( \"ui-corner-all ui-corner-left ui-corner-right\" )\n\t\t\t\t.filter( \":visible\" )\n\t\t\t\t\t.filter( \":first\" )\n\t\t\t\t\t\t.addClass( \"ui-corner-left\" )\n\t\t\t\t\t.end()\n\t\t\t\t\t.filter( \":last\" )\n\t\t\t\t\t\t.addClass( \"ui-corner-right\" )\n\t\t\t\t\t.end()\n\t\t\t\t.end()\n\t\t\t.end();\n\t},\n\n\tdestroy: function() {\n\t\tthis.element.removeClass( \"ui-buttonset\" );\n\t\tthis.buttons\n\t\t\t.map(function() {\n\t\t\t\treturn $( this ).button( \"widget\" )[ 0 ];\n\t\t\t})\n\t\t\t\t.removeClass( \"ui-corner-left ui-corner-right\" )\n\t\t\t.end()\n\t\t\t.button( \"destroy\" );\n\n\t\t$.Widget.prototype.destroy.call( this );\n\t}\n});\n\n}( jQuery ) );\n/*\n * jQuery UI Dialog 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Dialog\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.widget.js\n *  jquery.ui.button.js\n *\tjquery.ui.draggable.js\n *\tjquery.ui.mouse.js\n *\tjquery.ui.position.js\n *\tjquery.ui.resizable.js\n */\n(function( $, undefined ) {\n\nvar uiDialogClasses =\n\t\t'ui-dialog ' +\n\t\t'ui-widget ' +\n\t\t'ui-widget-content ' +\n\t\t'ui-corner-all ',\n\tsizeRelatedOptions = {\n\t\tbuttons: true,\n\t\theight: true,\n\t\tmaxHeight: true,\n\t\tmaxWidth: true,\n\t\tminHeight: true,\n\t\tminWidth: true,\n\t\twidth: true\n\t},\n\tresizableRelatedOptions = {\n\t\tmaxHeight: true,\n\t\tmaxWidth: true,\n\t\tminHeight: true,\n\t\tminWidth: true\n\t};\n\n$.widget(\"ui.dialog\", {\n\toptions: {\n\t\tautoOpen: true,\n\t\tbuttons: {},\n\t\tcloseOnEscape: true,\n\t\tcloseText: 'close',\n\t\tdialogClass: '',\n\t\tdraggable: true,\n\t\thide: null,\n\t\theight: 'auto',\n\t\tmaxHeight: false,\n\t\tmaxWidth: false,\n\t\tminHeight: 150,\n\t\tminWidth: 150,\n\t\tmodal: false,\n\t\tposition: {\n\t\t\tmy: 'center',\n\t\t\tat: 'center',\n\t\t\tof: window,\n\t\t\tcollision: 'fit',\n\t\t\t// ensure that the titlebar is never outside the document\n\t\t\tusing: function(pos) {\n\t\t\t\tvar topOffset = $(this).css(pos).offset().top;\n\t\t\t\tif (topOffset < 0) {\n\t\t\t\t\t$(this).css('top', pos.top - topOffset);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tresizable: true,\n\t\tshow: null,\n\t\tstack: true,\n\t\ttitle: '',\n\t\twidth: 300,\n\t\tzIndex: 1000\n\t},\n\n\t_create: function() {\n\t\tthis.originalTitle = this.element.attr('title');\n\t\t// #5742 - .attr() might return a DOMElement\n\t\tif ( typeof this.originalTitle !== \"string\" ) {\n\t\t\tthis.originalTitle = \"\";\n\t\t}\n\n\t\tthis.options.title = this.options.title || this.originalTitle;\n\t\tvar self = this,\n\t\t\toptions = self.options,\n\n\t\t\ttitle = options.title || '&#160;',\n\t\t\ttitleId = $.ui.dialog.getTitleId(self.element),\n\n\t\t\tuiDialog = (self.uiDialog = $('<div></div>'))\n\t\t\t\t.appendTo(document.body)\n\t\t\t\t.hide()\n\t\t\t\t.addClass(uiDialogClasses + options.dialogClass)\n\t\t\t\t.css({\n\t\t\t\t\tzIndex: options.zIndex\n\t\t\t\t})\n\t\t\t\t// setting tabIndex makes the div focusable\n\t\t\t\t// setting outline to 0 prevents a border on focus in Mozilla\n\t\t\t\t.attr('tabIndex', -1).css('outline', 0).keydown(function(event) {\n\t\t\t\t\tif (options.closeOnEscape && event.keyCode &&\n\t\t\t\t\t\tevent.keyCode === $.ui.keyCode.ESCAPE) {\n\t\t\t\t\t\t\n\t\t\t\t\t\tself.close(event);\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.attr({\n\t\t\t\t\trole: 'dialog',\n\t\t\t\t\t'aria-labelledby': titleId\n\t\t\t\t})\n\t\t\t\t.mousedown(function(event) {\n\t\t\t\t\tself.moveToTop(false, event);\n\t\t\t\t}),\n\n\t\t\tuiDialogContent = self.element\n\t\t\t\t.show()\n\t\t\t\t.removeAttr('title')\n\t\t\t\t.addClass(\n\t\t\t\t\t'ui-dialog-content ' +\n\t\t\t\t\t'ui-widget-content')\n\t\t\t\t.appendTo(uiDialog),\n\n\t\t\tuiDialogTitlebar = (self.uiDialogTitlebar = $('<div></div>'))\n\t\t\t\t.addClass(\n\t\t\t\t\t'ui-dialog-titlebar ' +\n\t\t\t\t\t'ui-widget-header ' +\n\t\t\t\t\t'ui-corner-all ' +\n\t\t\t\t\t'ui-helper-clearfix'\n\t\t\t\t)\n\t\t\t\t.prependTo(uiDialog),\n\n\t\t\tuiDialogTitlebarClose = $('<a href=\"#\"></a>')\n\t\t\t\t.addClass(\n\t\t\t\t\t'ui-dialog-titlebar-close ' +\n\t\t\t\t\t'ui-corner-all'\n\t\t\t\t)\n\t\t\t\t.attr('role', 'button')\n\t\t\t\t.hover(\n\t\t\t\t\tfunction() {\n\t\t\t\t\t\tuiDialogTitlebarClose.addClass('ui-state-hover');\n\t\t\t\t\t},\n\t\t\t\t\tfunction() {\n\t\t\t\t\t\tuiDialogTitlebarClose.removeClass('ui-state-hover');\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t\t.focus(function() {\n\t\t\t\t\tuiDialogTitlebarClose.addClass('ui-state-focus');\n\t\t\t\t})\n\t\t\t\t.blur(function() {\n\t\t\t\t\tuiDialogTitlebarClose.removeClass('ui-state-focus');\n\t\t\t\t})\n\t\t\t\t.click(function(event) {\n\t\t\t\t\tself.close(event);\n\t\t\t\t\treturn false;\n\t\t\t\t})\n\t\t\t\t.appendTo(uiDialogTitlebar),\n\n\t\t\tuiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('<span></span>'))\n\t\t\t\t.addClass(\n\t\t\t\t\t'ui-icon ' +\n\t\t\t\t\t'ui-icon-closethick'\n\t\t\t\t)\n\t\t\t\t.text(options.closeText)\n\t\t\t\t.appendTo(uiDialogTitlebarClose),\n\n\t\t\tuiDialogTitle = $('<span></span>')\n\t\t\t\t.addClass('ui-dialog-title')\n\t\t\t\t.attr('id', titleId)\n\t\t\t\t.html(title)\n\t\t\t\t.prependTo(uiDialogTitlebar);\n\n\t\t//handling of deprecated beforeclose (vs beforeClose) option\n\t\t//Ticket #4669 http://dev.jqueryui.com/ticket/4669\n\t\t//TODO: remove in 1.9pre\n\t\tif ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) {\n\t\t\toptions.beforeClose = options.beforeclose;\n\t\t}\n\n\t\tuiDialogTitlebar.find(\"*\").add(uiDialogTitlebar).disableSelection();\n\n\t\tif (options.draggable && $.fn.draggable) {\n\t\t\tself._makeDraggable();\n\t\t}\n\t\tif (options.resizable && $.fn.resizable) {\n\t\t\tself._makeResizable();\n\t\t}\n\n\t\tself._createButtons(options.buttons);\n\t\tself._isOpen = false;\n\n\t\tif ($.fn.bgiframe) {\n\t\t\tuiDialog.bgiframe();\n\t\t}\n\t},\n\n\t_init: function() {\n\t\tif ( this.options.autoOpen ) {\n\t\t\tthis.open();\n\t\t}\n\t},\n\n\tdestroy: function() {\n\t\tvar self = this;\n\t\t\n\t\tif (self.overlay) {\n\t\t\tself.overlay.destroy();\n\t\t}\n\t\tself.uiDialog.hide();\n\t\tself.element\n\t\t\t.unbind('.dialog')\n\t\t\t.removeData('dialog')\n\t\t\t.removeClass('ui-dialog-content ui-widget-content')\n\t\t\t.hide().appendTo('body');\n\t\tself.uiDialog.remove();\n\n\t\tif (self.originalTitle) {\n\t\t\tself.element.attr('title', self.originalTitle);\n\t\t}\n\n\t\treturn self;\n\t},\n\n\twidget: function() {\n\t\treturn this.uiDialog;\n\t},\n\n\tclose: function(event) {\n\t\tvar self = this,\n\t\t\tmaxZ;\n\t\t\n\t\tif (false === self._trigger('beforeClose', event)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (self.overlay) {\n\t\t\tself.overlay.destroy();\n\t\t}\n\t\tself.uiDialog.unbind('keypress.ui-dialog');\n\n\t\tself._isOpen = false;\n\n\t\tif (self.options.hide) {\n\t\t\tself.uiDialog.hide(self.options.hide, function() {\n\t\t\t\tself._trigger('close', event);\n\t\t\t});\n\t\t} else {\n\t\t\tself.uiDialog.hide();\n\t\t\tself._trigger('close', event);\n\t\t}\n\n\t\t$.ui.dialog.overlay.resize();\n\n\t\t// adjust the maxZ to allow other modal dialogs to continue to work (see #4309)\n\t\tif (self.options.modal) {\n\t\t\tmaxZ = 0;\n\t\t\t$('.ui-dialog').each(function() {\n\t\t\t\tif (this !== self.uiDialog[0]) {\n\t\t\t\t\tmaxZ = Math.max(maxZ, $(this).css('z-index'));\n\t\t\t\t}\n\t\t\t});\n\t\t\t$.ui.dialog.maxZ = maxZ;\n\t\t}\n\n\t\treturn self;\n\t},\n\n\tisOpen: function() {\n\t\treturn this._isOpen;\n\t},\n\n\t// the force parameter allows us to move modal dialogs to their correct\n\t// position on open\n\tmoveToTop: function(force, event) {\n\t\tvar self = this,\n\t\t\toptions = self.options,\n\t\t\tsaveScroll;\n\n\t\tif ((options.modal && !force) ||\n\t\t\t(!options.stack && !options.modal)) {\n\t\t\treturn self._trigger('focus', event);\n\t\t}\n\n\t\tif (options.zIndex > $.ui.dialog.maxZ) {\n\t\t\t$.ui.dialog.maxZ = options.zIndex;\n\t\t}\n\t\tif (self.overlay) {\n\t\t\t$.ui.dialog.maxZ += 1;\n\t\t\tself.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ);\n\t\t}\n\n\t\t//Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed.\n\t\t//  http://ui.jquery.com/bugs/ticket/3193\n\t\tsaveScroll = { scrollTop: self.element.attr('scrollTop'), scrollLeft: self.element.attr('scrollLeft') };\n\t\t$.ui.dialog.maxZ += 1;\n\t\tself.uiDialog.css('z-index', $.ui.dialog.maxZ);\n\t\tself.element.attr(saveScroll);\n\t\tself._trigger('focus', event);\n\n\t\treturn self;\n\t},\n\n\topen: function() {\n\t\tif (this._isOpen) { return; }\n\n\t\tvar self = this,\n\t\t\toptions = self.options,\n\t\t\tuiDialog = self.uiDialog;\n\n\t\tself.overlay = options.modal ? new $.ui.dialog.overlay(self) : null;\n\t\tself._size();\n\t\tself._position(options.position);\n\t\tuiDialog.show(options.show);\n\t\tself.moveToTop(true);\n\n\t\t// prevent tabbing out of modal dialogs\n\t\tif (options.modal) {\n\t\t\tuiDialog.bind('keypress.ui-dialog', function(event) {\n\t\t\t\tif (event.keyCode !== $.ui.keyCode.TAB) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar tabbables = $(':tabbable', this),\n\t\t\t\t\tfirst = tabbables.filter(':first'),\n\t\t\t\t\tlast  = tabbables.filter(':last');\n\n\t\t\t\tif (event.target === last[0] && !event.shiftKey) {\n\t\t\t\t\tfirst.focus(1);\n\t\t\t\t\treturn false;\n\t\t\t\t} else if (event.target === first[0] && event.shiftKey) {\n\t\t\t\t\tlast.focus(1);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// set focus to the first tabbable element in the content area or the first button\n\t\t// if there are no tabbable elements, set focus on the dialog itself\n\t\t$(self.element.find(':tabbable').get().concat(\n\t\t\tuiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat(\n\t\t\t\tuiDialog.get()))).eq(0).focus();\n\n\t\tself._isOpen = true;\n\t\tself._trigger('open');\n\n\t\treturn self;\n\t},\n\n\t_createButtons: function(buttons) {\n\t\tvar self = this,\n\t\t\thasButtons = false,\n\t\t\tuiDialogButtonPane = $('<div></div>')\n\t\t\t\t.addClass(\n\t\t\t\t\t'ui-dialog-buttonpane ' +\n\t\t\t\t\t'ui-widget-content ' +\n\t\t\t\t\t'ui-helper-clearfix'\n\t\t\t\t),\n\t\t\tuiButtonSet = $( \"<div></div>\" )\n\t\t\t\t.addClass( \"ui-dialog-buttonset\" )\n\t\t\t\t.appendTo( uiDialogButtonPane );\n\n\t\t// if we already have a button pane, remove it\n\t\tself.uiDialog.find('.ui-dialog-buttonpane').remove();\n\n\t\tif (typeof buttons === 'object' && buttons !== null) {\n\t\t\t$.each(buttons, function() {\n\t\t\t\treturn !(hasButtons = true);\n\t\t\t});\n\t\t}\n\t\tif (hasButtons) {\n\t\t\t$.each(buttons, function(name, props) {\n\t\t\t\tprops = $.isFunction( props ) ?\n\t\t\t\t\t{ click: props, text: name } :\n\t\t\t\t\tprops;\n\t\t\t\tvar button = $('<button type=\"button\"></button>')\n\t\t\t\t\t.attr( props, true )\n\t\t\t\t\t.unbind('click')\n\t\t\t\t\t.click(function() {\n\t\t\t\t\t\tprops.click.apply(self.element[0], arguments);\n\t\t\t\t\t})\n\t\t\t\t\t.appendTo(uiButtonSet);\n\t\t\t\tif ($.fn.button) {\n\t\t\t\t\tbutton.button();\n\t\t\t\t}\n\t\t\t});\n\t\t\tuiDialogButtonPane.appendTo(self.uiDialog);\n\t\t}\n\t},\n\n\t_makeDraggable: function() {\n\t\tvar self = this,\n\t\t\toptions = self.options,\n\t\t\tdoc = $(document),\n\t\t\theightBeforeDrag;\n\n\t\tfunction filteredUi(ui) {\n\t\t\treturn {\n\t\t\t\tposition: ui.position,\n\t\t\t\toffset: ui.offset\n\t\t\t};\n\t\t}\n\n\t\tself.uiDialog.draggable({\n\t\t\tcancel: '.ui-dialog-content, .ui-dialog-titlebar-close',\n\t\t\thandle: '.ui-dialog-titlebar',\n\t\t\tcontainment: 'document',\n\t\t\tstart: function(event, ui) {\n\t\t\t\theightBeforeDrag = options.height === \"auto\" ? \"auto\" : $(this).height();\n\t\t\t\t$(this).height($(this).height()).addClass(\"ui-dialog-dragging\");\n\t\t\t\tself._trigger('dragStart', event, filteredUi(ui));\n\t\t\t},\n\t\t\tdrag: function(event, ui) {\n\t\t\t\tself._trigger('drag', event, filteredUi(ui));\n\t\t\t},\n\t\t\tstop: function(event, ui) {\n\t\t\t\toptions.position = [ui.position.left - doc.scrollLeft(),\n\t\t\t\t\tui.position.top - doc.scrollTop()];\n\t\t\t\t$(this).removeClass(\"ui-dialog-dragging\").height(heightBeforeDrag);\n\t\t\t\tself._trigger('dragStop', event, filteredUi(ui));\n\t\t\t\t$.ui.dialog.overlay.resize();\n\t\t\t}\n\t\t});\n\t},\n\n\t_makeResizable: function(handles) {\n\t\thandles = (handles === undefined ? this.options.resizable : handles);\n\t\tvar self = this,\n\t\t\toptions = self.options,\n\t\t\t// .ui-resizable has position: relative defined in the stylesheet\n\t\t\t// but dialogs have to use absolute or fixed positioning\n\t\t\tposition = self.uiDialog.css('position'),\n\t\t\tresizeHandles = (typeof handles === 'string' ?\n\t\t\t\thandles\t:\n\t\t\t\t'n,e,s,w,se,sw,ne,nw'\n\t\t\t);\n\n\t\tfunction filteredUi(ui) {\n\t\t\treturn {\n\t\t\t\toriginalPosition: ui.originalPosition,\n\t\t\t\toriginalSize: ui.originalSize,\n\t\t\t\tposition: ui.position,\n\t\t\t\tsize: ui.size\n\t\t\t};\n\t\t}\n\n\t\tself.uiDialog.resizable({\n\t\t\tcancel: '.ui-dialog-content',\n\t\t\tcontainment: 'document',\n\t\t\talsoResize: self.element,\n\t\t\tmaxWidth: options.maxWidth,\n\t\t\tmaxHeight: options.maxHeight,\n\t\t\tminWidth: options.minWidth,\n\t\t\tminHeight: self._minHeight(),\n\t\t\thandles: resizeHandles,\n\t\t\tstart: function(event, ui) {\n\t\t\t\t$(this).addClass(\"ui-dialog-resizing\");\n\t\t\t\tself._trigger('resizeStart', event, filteredUi(ui));\n\t\t\t},\n\t\t\tresize: function(event, ui) {\n\t\t\t\tself._trigger('resize', event, filteredUi(ui));\n\t\t\t},\n\t\t\tstop: function(event, ui) {\n\t\t\t\t$(this).removeClass(\"ui-dialog-resizing\");\n\t\t\t\toptions.height = $(this).height();\n\t\t\t\toptions.width = $(this).width();\n\t\t\t\tself._trigger('resizeStop', event, filteredUi(ui));\n\t\t\t\t$.ui.dialog.overlay.resize();\n\t\t\t}\n\t\t})\n\t\t.css('position', position)\n\t\t.find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');\n\t},\n\n\t_minHeight: function() {\n\t\tvar options = this.options;\n\n\t\tif (options.height === 'auto') {\n\t\t\treturn options.minHeight;\n\t\t} else {\n\t\t\treturn Math.min(options.minHeight, options.height);\n\t\t}\n\t},\n\n\t_position: function(position) {\n\t\tvar myAt = [],\n\t\t\toffset = [0, 0],\n\t\t\tisVisible;\n\n\t\tif (position) {\n\t\t\t// deep extending converts arrays to objects in jQuery <= 1.3.2 :-(\n\t//\t\tif (typeof position == 'string' || $.isArray(position)) {\n\t//\t\t\tmyAt = $.isArray(position) ? position : position.split(' ');\n\n\t\t\tif (typeof position === 'string' || (typeof position === 'object' && '0' in position)) {\n\t\t\t\tmyAt = position.split ? position.split(' ') : [position[0], position[1]];\n\t\t\t\tif (myAt.length === 1) {\n\t\t\t\t\tmyAt[1] = myAt[0];\n\t\t\t\t}\n\n\t\t\t\t$.each(['left', 'top'], function(i, offsetPosition) {\n\t\t\t\t\tif (+myAt[i] === myAt[i]) {\n\t\t\t\t\t\toffset[i] = myAt[i];\n\t\t\t\t\t\tmyAt[i] = offsetPosition;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tposition = {\n\t\t\t\t\tmy: myAt.join(\" \"),\n\t\t\t\t\tat: myAt.join(\" \"),\n\t\t\t\t\toffset: offset.join(\" \")\n\t\t\t\t};\n\t\t\t} \n\n\t\t\tposition = $.extend({}, $.ui.dialog.prototype.options.position, position);\n\t\t} else {\n\t\t\tposition = $.ui.dialog.prototype.options.position;\n\t\t}\n\n\t\t// need to show the dialog to get the actual offset in the position plugin\n\t\tisVisible = this.uiDialog.is(':visible');\n\t\tif (!isVisible) {\n\t\t\tthis.uiDialog.show();\n\t\t}\n\t\tthis.uiDialog\n\t\t\t// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781\n\t\t\t.css({ top: 0, left: 0 })\n\t\t\t.position(position);\n\t\tif (!isVisible) {\n\t\t\tthis.uiDialog.hide();\n\t\t}\n\t},\n\n\t_setOptions: function( options ) {\n\t\tvar self = this,\n\t\t\tresizableOptions = {},\n\t\t\tresize = false;\n\n\t\t$.each( options, function( key, value ) {\n\t\t\tself._setOption( key, value );\n\t\t\t\n\t\t\tif ( key in sizeRelatedOptions ) {\n\t\t\t\tresize = true;\n\t\t\t}\n\t\t\tif ( key in resizableRelatedOptions ) {\n\t\t\t\tresizableOptions[ key ] = value;\n\t\t\t}\n\t\t});\n\n\t\tif ( resize ) {\n\t\t\tthis._size();\n\t\t}\n\t\tif ( this.uiDialog.is( \":data(resizable)\" ) ) {\n\t\t\tthis.uiDialog.resizable( \"option\", resizableOptions );\n\t\t}\n\t},\n\n\t_setOption: function(key, value){\n\t\tvar self = this,\n\t\t\tuiDialog = self.uiDialog;\n\n\t\tswitch (key) {\n\t\t\t//handling of deprecated beforeclose (vs beforeClose) option\n\t\t\t//Ticket #4669 http://dev.jqueryui.com/ticket/4669\n\t\t\t//TODO: remove in 1.9pre\n\t\t\tcase \"beforeclose\":\n\t\t\t\tkey = \"beforeClose\";\n\t\t\t\tbreak;\n\t\t\tcase \"buttons\":\n\t\t\t\tself._createButtons(value);\n\t\t\t\tbreak;\n\t\t\tcase \"closeText\":\n\t\t\t\t// ensure that we always pass a string\n\t\t\t\tself.uiDialogTitlebarCloseText.text(\"\" + value);\n\t\t\t\tbreak;\n\t\t\tcase \"dialogClass\":\n\t\t\t\tuiDialog\n\t\t\t\t\t.removeClass(self.options.dialogClass)\n\t\t\t\t\t.addClass(uiDialogClasses + value);\n\t\t\t\tbreak;\n\t\t\tcase \"disabled\":\n\t\t\t\tif (value) {\n\t\t\t\t\tuiDialog.addClass('ui-dialog-disabled');\n\t\t\t\t} else {\n\t\t\t\t\tuiDialog.removeClass('ui-dialog-disabled');\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"draggable\":\n\t\t\t\tvar isDraggable = uiDialog.is( \":data(draggable)\" )\n\t\t\t\tif ( isDraggable && !value ) {\n\t\t\t\t\tuiDialog.draggable( \"destroy\" );\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( !isDraggable && value ) {\n\t\t\t\t\tself._makeDraggable();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"position\":\n\t\t\t\tself._position(value);\n\t\t\t\tbreak;\n\t\t\tcase \"resizable\":\n\t\t\t\t// currently resizable, becoming non-resizable\n\t\t\t\tvar isResizable = uiDialog.is( \":data(resizable)\" )\n\t\t\t\tif (isResizable && !value) {\n\t\t\t\t\tuiDialog.resizable('destroy');\n\t\t\t\t}\n\n\t\t\t\t// currently resizable, changing handles\n\t\t\t\tif (isResizable && typeof value === 'string') {\n\t\t\t\t\tuiDialog.resizable('option', 'handles', value);\n\t\t\t\t}\n\n\t\t\t\t// currently non-resizable, becoming resizable\n\t\t\t\tif (!isResizable && value !== false) {\n\t\t\t\t\tself._makeResizable(value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"title\":\n\t\t\t\t// convert whatever was passed in o a string, for html() to not throw up\n\t\t\t\t$(\".ui-dialog-title\", self.uiDialogTitlebar).html(\"\" + (value || '&#160;'));\n\t\t\t\tbreak;\n\t\t}\n\n\t\t$.Widget.prototype._setOption.apply(self, arguments);\n\t},\n\n\t_size: function() {\n\t\t/* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content\n\t\t * divs will both have width and height set, so we need to reset them\n\t\t */\n\t\tvar options = this.options,\n\t\t\tnonContentHeight,\n\t\t\tminContentHeight;\n\n\t\t// reset content sizing\n\t\tthis.element.show().css({\n\t\t\twidth: 'auto',\n\t\t\tminHeight: 0,\n\t\t\theight: 0\n\t\t});\n\n\t\tif (options.minWidth > options.width) {\n\t\t\toptions.width = options.minWidth;\n\t\t}\n\n\t\t// reset wrapper sizing\n\t\t// determine the height of all the non-content elements\n\t\tnonContentHeight = this.uiDialog.css({\n\t\t\t\theight: 'auto',\n\t\t\t\twidth: options.width\n\t\t\t})\n\t\t\t.height();\n\t\tminContentHeight = Math.max( 0, options.minHeight - nonContentHeight );\n\t\t\n\t\tif ( options.height === \"auto\" ) {\n\t\t\t// only needed for IE6 support\n\t\t\tif ( $.support.minHeight ) {\n\t\t\t\tthis.element.css({\n\t\t\t\t\tminHeight: minContentHeight,\n\t\t\t\t\theight: \"auto\"\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis.uiDialog.show();\n\t\t\t\tvar autoHeight = this.element.css( \"height\", \"auto\" ).height();\n\t\t\t\tthis.uiDialog.hide();\n\t\t\t\tthis.element.height( Math.max( autoHeight, minContentHeight ) );\n\t\t\t}\n\t\t} else {\n\t\t\tthis.element.height( Math.max( options.height - nonContentHeight, 0 ) );\n\t\t}\n\n\t\tif (this.uiDialog.is(':data(resizable)')) {\n\t\t\tthis.uiDialog.resizable('option', 'minHeight', this._minHeight());\n\t\t}\n\t}\n});\n\n$.extend($.ui.dialog, {\n\tversion: \"1.8.6\",\n\n\tuuid: 0,\n\tmaxZ: 0,\n\n\tgetTitleId: function($el) {\n\t\tvar id = $el.attr('id');\n\t\tif (!id) {\n\t\t\tthis.uuid += 1;\n\t\t\tid = this.uuid;\n\t\t}\n\t\treturn 'ui-dialog-title-' + id;\n\t},\n\n\toverlay: function(dialog) {\n\t\tthis.$el = $.ui.dialog.overlay.create(dialog);\n\t}\n});\n\n$.extend($.ui.dialog.overlay, {\n\tinstances: [],\n\t// reuse old instances due to IE memory leak with alpha transparency (see #5185)\n\toldInstances: [],\n\tmaxZ: 0,\n\tevents: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),\n\t\tfunction(event) { return event + '.dialog-overlay'; }).join(' '),\n\tcreate: function(dialog) {\n\t\tif (this.instances.length === 0) {\n\t\t\t// prevent use of anchors and inputs\n\t\t\t// we use a setTimeout in case the overlay is created from an\n\t\t\t// event that we're going to be cancelling (see #2804)\n\t\t\tsetTimeout(function() {\n\t\t\t\t// handle $(el).dialog().dialog('close') (see #4065)\n\t\t\t\tif ($.ui.dialog.overlay.instances.length) {\n\t\t\t\t\t$(document).bind($.ui.dialog.overlay.events, function(event) {\n\t\t\t\t\t\t// stop events if the z-index of the target is < the z-index of the overlay\n\t\t\t\t\t\t// we cannot return true when we don't want to cancel the event (#3523)\n\t\t\t\t\t\tif ($(event.target).zIndex() < $.ui.dialog.overlay.maxZ) {\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}\n\t\t\t}, 1);\n\n\t\t\t// allow closing by pressing the escape key\n\t\t\t$(document).bind('keydown.dialog-overlay', function(event) {\n\t\t\t\tif (dialog.options.closeOnEscape && event.keyCode &&\n\t\t\t\t\tevent.keyCode === $.ui.keyCode.ESCAPE) {\n\t\t\t\t\t\n\t\t\t\t\tdialog.close(event);\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// handle window resize\n\t\t\t$(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);\n\t\t}\n\n\t\tvar $el = (this.oldInstances.pop() || $('<div></div>').addClass('ui-widget-overlay'))\n\t\t\t.appendTo(document.body)\n\t\t\t.css({\n\t\t\t\twidth: this.width(),\n\t\t\t\theight: this.height()\n\t\t\t});\n\n\t\tif ($.fn.bgiframe) {\n\t\t\t$el.bgiframe();\n\t\t}\n\n\t\tthis.instances.push($el);\n\t\treturn $el;\n\t},\n\n\tdestroy: function($el) {\n\t\tthis.oldInstances.push(this.instances.splice($.inArray($el, this.instances), 1)[0]);\n\n\t\tif (this.instances.length === 0) {\n\t\t\t$([document, window]).unbind('.dialog-overlay');\n\t\t}\n\n\t\t$el.remove();\n\t\t\n\t\t// adjust the maxZ to allow other modal dialogs to continue to work (see #4309)\n\t\tvar maxZ = 0;\n\t\t$.each(this.instances, function() {\n\t\t\tmaxZ = Math.max(maxZ, this.css('z-index'));\n\t\t});\n\t\tthis.maxZ = maxZ;\n\t},\n\n\theight: function() {\n\t\tvar scrollHeight,\n\t\t\toffsetHeight;\n\t\t// handle IE 6\n\t\tif ($.browser.msie && $.browser.version < 7) {\n\t\t\tscrollHeight = Math.max(\n\t\t\t\tdocument.documentElement.scrollHeight,\n\t\t\t\tdocument.body.scrollHeight\n\t\t\t);\n\t\t\toffsetHeight = Math.max(\n\t\t\t\tdocument.documentElement.offsetHeight,\n\t\t\t\tdocument.body.offsetHeight\n\t\t\t);\n\n\t\t\tif (scrollHeight < offsetHeight) {\n\t\t\t\treturn $(window).height() + 'px';\n\t\t\t} else {\n\t\t\t\treturn scrollHeight + 'px';\n\t\t\t}\n\t\t// handle \"good\" browsers\n\t\t} else {\n\t\t\treturn $(document).height() + 'px';\n\t\t}\n\t},\n\n\twidth: function() {\n\t\tvar scrollWidth,\n\t\t\toffsetWidth;\n\t\t// handle IE 6\n\t\tif ($.browser.msie && $.browser.version < 7) {\n\t\t\tscrollWidth = Math.max(\n\t\t\t\tdocument.documentElement.scrollWidth,\n\t\t\t\tdocument.body.scrollWidth\n\t\t\t);\n\t\t\toffsetWidth = Math.max(\n\t\t\t\tdocument.documentElement.offsetWidth,\n\t\t\t\tdocument.body.offsetWidth\n\t\t\t);\n\n\t\t\tif (scrollWidth < offsetWidth) {\n\t\t\t\treturn $(window).width() + 'px';\n\t\t\t} else {\n\t\t\t\treturn scrollWidth + 'px';\n\t\t\t}\n\t\t// handle \"good\" browsers\n\t\t} else {\n\t\t\treturn $(document).width() + 'px';\n\t\t}\n\t},\n\n\tresize: function() {\n\t\t/* If the dialog is draggable and the user drags it past the\n\t\t * right edge of the window, the document becomes wider so we\n\t\t * need to stretch the overlay. If the user then drags the\n\t\t * dialog back to the left, the document will become narrower,\n\t\t * so we need to shrink the overlay to the appropriate size.\n\t\t * This is handled by shrinking the overlay before setting it\n\t\t * to the full document size.\n\t\t */\n\t\tvar $overlays = $([]);\n\t\t$.each($.ui.dialog.overlay.instances, function() {\n\t\t\t$overlays = $overlays.add(this);\n\t\t});\n\n\t\t$overlays.css({\n\t\t\twidth: 0,\n\t\t\theight: 0\n\t\t}).css({\n\t\t\twidth: $.ui.dialog.overlay.width(),\n\t\t\theight: $.ui.dialog.overlay.height()\n\t\t});\n\t}\n});\n\n$.extend($.ui.dialog.overlay.prototype, {\n\tdestroy: function() {\n\t\t$.ui.dialog.overlay.destroy(this.$el);\n\t}\n});\n\n}(jQuery));\n/*\n * jQuery UI Slider 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Slider\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.mouse.js\n *\tjquery.ui.widget.js\n */\n(function( $, undefined ) {\n\n// number of pages in a slider\n// (how many times can you page up/down to go through the whole range)\nvar numPages = 5;\n\n$.widget( \"ui.slider\", $.ui.mouse, {\n\n\twidgetEventPrefix: \"slide\",\n\n\toptions: {\n\t\tanimate: false,\n\t\tdistance: 0,\n\t\tmax: 100,\n\t\tmin: 0,\n\t\torientation: \"horizontal\",\n\t\trange: false,\n\t\tstep: 1,\n\t\tvalue: 0,\n\t\tvalues: null\n\t},\n\n\t_create: function() {\n\t\tvar self = this,\n\t\t\to = this.options;\n\n\t\tthis._keySliding = false;\n\t\tthis._mouseSliding = false;\n\t\tthis._animateOff = true;\n\t\tthis._handleIndex = null;\n\t\tthis._detectOrientation();\n\t\tthis._mouseInit();\n\n\t\tthis.element\n\t\t\t.addClass( \"ui-slider\" +\n\t\t\t\t\" ui-slider-\" + this.orientation +\n\t\t\t\t\" ui-widget\" +\n\t\t\t\t\" ui-widget-content\" +\n\t\t\t\t\" ui-corner-all\" );\n\t\t\n\t\tif ( o.disabled ) {\n\t\t\tthis.element.addClass( \"ui-slider-disabled ui-disabled\" );\n\t\t}\n\n\t\tthis.range = $([]);\n\n\t\tif ( o.range ) {\n\t\t\tif ( o.range === true ) {\n\t\t\t\tthis.range = $( \"<div></div>\" );\n\t\t\t\tif ( !o.values ) {\n\t\t\t\t\to.values = [ this._valueMin(), this._valueMin() ];\n\t\t\t\t}\n\t\t\t\tif ( o.values.length && o.values.length !== 2 ) {\n\t\t\t\t\to.values = [ o.values[0], o.values[0] ];\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.range = $( \"<div></div>\" );\n\t\t\t}\n\n\t\t\tthis.range\n\t\t\t\t.appendTo( this.element )\n\t\t\t\t.addClass( \"ui-slider-range\" );\n\n\t\t\tif ( o.range === \"min\" || o.range === \"max\" ) {\n\t\t\t\tthis.range.addClass( \"ui-slider-range-\" + o.range );\n\t\t\t}\n\n\t\t\t// note: this isn't the most fittingly semantic framework class for this element,\n\t\t\t// but worked best visually with a variety of themes\n\t\t\tthis.range.addClass( \"ui-widget-header\" );\n\t\t}\n\n\t\tif ( $( \".ui-slider-handle\", this.element ).length === 0 ) {\n\t\t\t$( \"<a href='#'></a>\" )\n\t\t\t\t.appendTo( this.element )\n\t\t\t\t.addClass( \"ui-slider-handle\" );\n\t\t}\n\n\t\tif ( o.values && o.values.length ) {\n\t\t\twhile ( $(\".ui-slider-handle\", this.element).length < o.values.length ) {\n\t\t\t\t$( \"<a href='#'></a>\" )\n\t\t\t\t\t.appendTo( this.element )\n\t\t\t\t\t.addClass( \"ui-slider-handle\" );\n\t\t\t}\n\t\t}\n\n\t\tthis.handles = $( \".ui-slider-handle\", this.element )\n\t\t\t.addClass( \"ui-state-default\" +\n\t\t\t\t\" ui-corner-all\" );\n\n\t\tthis.handle = this.handles.eq( 0 );\n\n\t\tthis.handles.add( this.range ).filter( \"a\" )\n\t\t\t.click(function( event ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t})\n\t\t\t.hover(function() {\n\t\t\t\tif ( !o.disabled ) {\n\t\t\t\t\t$( this ).addClass( \"ui-state-hover\" );\n\t\t\t\t}\n\t\t\t}, function() {\n\t\t\t\t$( this ).removeClass( \"ui-state-hover\" );\n\t\t\t})\n\t\t\t.focus(function() {\n\t\t\t\tif ( !o.disabled ) {\n\t\t\t\t\t$( \".ui-slider .ui-state-focus\" ).removeClass( \"ui-state-focus\" );\n\t\t\t\t\t$( this ).addClass( \"ui-state-focus\" );\n\t\t\t\t} else {\n\t\t\t\t\t$( this ).blur();\n\t\t\t\t}\n\t\t\t})\n\t\t\t.blur(function() {\n\t\t\t\t$( this ).removeClass( \"ui-state-focus\" );\n\t\t\t});\n\n\t\tthis.handles.each(function( i ) {\n\t\t\t$( this ).data( \"index.ui-slider-handle\", i );\n\t\t});\n\n\t\tthis.handles\n\t\t\t.keydown(function( event ) {\n\t\t\t\tvar ret = true,\n\t\t\t\t\tindex = $( this ).data( \"index.ui-slider-handle\" ),\n\t\t\t\t\tallowed,\n\t\t\t\t\tcurVal,\n\t\t\t\t\tnewVal,\n\t\t\t\t\tstep;\n\t\n\t\t\t\tif ( self.options.disabled ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tswitch ( event.keyCode ) {\n\t\t\t\t\tcase $.ui.keyCode.HOME:\n\t\t\t\t\tcase $.ui.keyCode.END:\n\t\t\t\t\tcase $.ui.keyCode.PAGE_UP:\n\t\t\t\t\tcase $.ui.keyCode.PAGE_DOWN:\n\t\t\t\t\tcase $.ui.keyCode.UP:\n\t\t\t\t\tcase $.ui.keyCode.RIGHT:\n\t\t\t\t\tcase $.ui.keyCode.DOWN:\n\t\t\t\t\tcase $.ui.keyCode.LEFT:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tif ( !self._keySliding ) {\n\t\t\t\t\t\t\tself._keySliding = true;\n\t\t\t\t\t\t\t$( this ).addClass( \"ui-state-active\" );\n\t\t\t\t\t\t\tallowed = self._start( event, index );\n\t\t\t\t\t\t\tif ( allowed === false ) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\n\t\t\t\tstep = self.options.step;\n\t\t\t\tif ( self.options.values && self.options.values.length ) {\n\t\t\t\t\tcurVal = newVal = self.values( index );\n\t\t\t\t} else {\n\t\t\t\t\tcurVal = newVal = self.value();\n\t\t\t\t}\n\t\n\t\t\t\tswitch ( event.keyCode ) {\n\t\t\t\t\tcase $.ui.keyCode.HOME:\n\t\t\t\t\t\tnewVal = self._valueMin();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.END:\n\t\t\t\t\t\tnewVal = self._valueMax();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.PAGE_UP:\n\t\t\t\t\t\tnewVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.PAGE_DOWN:\n\t\t\t\t\t\tnewVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.UP:\n\t\t\t\t\tcase $.ui.keyCode.RIGHT:\n\t\t\t\t\t\tif ( curVal === self._valueMax() ) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnewVal = self._trimAlignValue( curVal + step );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.DOWN:\n\t\t\t\t\tcase $.ui.keyCode.LEFT:\n\t\t\t\t\t\tif ( curVal === self._valueMin() ) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnewVal = self._trimAlignValue( curVal - step );\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\n\t\t\t\tself._slide( event, index, newVal );\n\t\n\t\t\t\treturn ret;\n\t\n\t\t\t})\n\t\t\t.keyup(function( event ) {\n\t\t\t\tvar index = $( this ).data( \"index.ui-slider-handle\" );\n\t\n\t\t\t\tif ( self._keySliding ) {\n\t\t\t\t\tself._keySliding = false;\n\t\t\t\t\tself._stop( event, index );\n\t\t\t\t\tself._change( event, index );\n\t\t\t\t\t$( this ).removeClass( \"ui-state-active\" );\n\t\t\t\t}\n\t\n\t\t\t});\n\n\t\tthis._refreshValue();\n\n\t\tthis._animateOff = false;\n\t},\n\n\tdestroy: function() {\n\t\tthis.handles.remove();\n\t\tthis.range.remove();\n\n\t\tthis.element\n\t\t\t.removeClass( \"ui-slider\" +\n\t\t\t\t\" ui-slider-horizontal\" +\n\t\t\t\t\" ui-slider-vertical\" +\n\t\t\t\t\" ui-slider-disabled\" +\n\t\t\t\t\" ui-widget\" +\n\t\t\t\t\" ui-widget-content\" +\n\t\t\t\t\" ui-corner-all\" )\n\t\t\t.removeData( \"slider\" )\n\t\t\t.unbind( \".slider\" );\n\n\t\tthis._mouseDestroy();\n\n\t\treturn this;\n\t},\n\n\t_mouseCapture: function( event ) {\n\t\tvar o = this.options,\n\t\t\tposition,\n\t\t\tnormValue,\n\t\t\tdistance,\n\t\t\tclosestHandle,\n\t\t\tself,\n\t\t\tindex,\n\t\t\tallowed,\n\t\t\toffset,\n\t\t\tmouseOverHandle;\n\n\t\tif ( o.disabled ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.elementSize = {\n\t\t\twidth: this.element.outerWidth(),\n\t\t\theight: this.element.outerHeight()\n\t\t};\n\t\tthis.elementOffset = this.element.offset();\n\n\t\tposition = { x: event.pageX, y: event.pageY };\n\t\tnormValue = this._normValueFromMouse( position );\n\t\tdistance = this._valueMax() - this._valueMin() + 1;\n\t\tself = this;\n\t\tthis.handles.each(function( i ) {\n\t\t\tvar thisDistance = Math.abs( normValue - self.values(i) );\n\t\t\tif ( distance > thisDistance ) {\n\t\t\t\tdistance = thisDistance;\n\t\t\t\tclosestHandle = $( this );\n\t\t\t\tindex = i;\n\t\t\t}\n\t\t});\n\n\t\t// workaround for bug #3736 (if both handles of a range are at 0,\n\t\t// the first is always used as the one with least distance,\n\t\t// and moving it is obviously prevented by preventing negative ranges)\n\t\tif( o.range === true && this.values(1) === o.min ) {\n\t\t\tindex += 1;\n\t\t\tclosestHandle = $( this.handles[index] );\n\t\t}\n\n\t\tallowed = this._start( event, index );\n\t\tif ( allowed === false ) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._mouseSliding = true;\n\n\t\tself._handleIndex = index;\n\n\t\tclosestHandle\n\t\t\t.addClass( \"ui-state-active\" )\n\t\t\t.focus();\n\t\t\n\t\toffset = closestHandle.offset();\n\t\tmouseOverHandle = !$( event.target ).parents().andSelf().is( \".ui-slider-handle\" );\n\t\tthis._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {\n\t\t\tleft: event.pageX - offset.left - ( closestHandle.width() / 2 ),\n\t\t\ttop: event.pageY - offset.top -\n\t\t\t\t( closestHandle.height() / 2 ) -\n\t\t\t\t( parseInt( closestHandle.css(\"borderTopWidth\"), 10 ) || 0 ) -\n\t\t\t\t( parseInt( closestHandle.css(\"borderBottomWidth\"), 10 ) || 0) +\n\t\t\t\t( parseInt( closestHandle.css(\"marginTop\"), 10 ) || 0)\n\t\t};\n\n\t\tthis._slide( event, index, normValue );\n\t\tthis._animateOff = true;\n\t\treturn true;\n\t},\n\n\t_mouseStart: function( event ) {\n\t\treturn true;\n\t},\n\n\t_mouseDrag: function( event ) {\n\t\tvar position = { x: event.pageX, y: event.pageY },\n\t\t\tnormValue = this._normValueFromMouse( position );\n\t\t\n\t\tthis._slide( event, this._handleIndex, normValue );\n\n\t\treturn false;\n\t},\n\n\t_mouseStop: function( event ) {\n\t\tthis.handles.removeClass( \"ui-state-active\" );\n\t\tthis._mouseSliding = false;\n\n\t\tthis._stop( event, this._handleIndex );\n\t\tthis._change( event, this._handleIndex );\n\n\t\tthis._handleIndex = null;\n\t\tthis._clickOffset = null;\n\t\tthis._animateOff = false;\n\n\t\treturn false;\n\t},\n\t\n\t_detectOrientation: function() {\n\t\tthis.orientation = ( this.options.orientation === \"vertical\" ) ? \"vertical\" : \"horizontal\";\n\t},\n\n\t_normValueFromMouse: function( position ) {\n\t\tvar pixelTotal,\n\t\t\tpixelMouse,\n\t\t\tpercentMouse,\n\t\t\tvalueTotal,\n\t\t\tvalueMouse;\n\n\t\tif ( this.orientation === \"horizontal\" ) {\n\t\t\tpixelTotal = this.elementSize.width;\n\t\t\tpixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );\n\t\t} else {\n\t\t\tpixelTotal = this.elementSize.height;\n\t\t\tpixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );\n\t\t}\n\n\t\tpercentMouse = ( pixelMouse / pixelTotal );\n\t\tif ( percentMouse > 1 ) {\n\t\t\tpercentMouse = 1;\n\t\t}\n\t\tif ( percentMouse < 0 ) {\n\t\t\tpercentMouse = 0;\n\t\t}\n\t\tif ( this.orientation === \"vertical\" ) {\n\t\t\tpercentMouse = 1 - percentMouse;\n\t\t}\n\n\t\tvalueTotal = this._valueMax() - this._valueMin();\n\t\tvalueMouse = this._valueMin() + percentMouse * valueTotal;\n\n\t\treturn this._trimAlignValue( valueMouse );\n\t},\n\n\t_start: function( event, index ) {\n\t\tvar uiHash = {\n\t\t\thandle: this.handles[ index ],\n\t\t\tvalue: this.value()\n\t\t};\n\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\tuiHash.value = this.values( index );\n\t\t\tuiHash.values = this.values();\n\t\t}\n\t\treturn this._trigger( \"start\", event, uiHash );\n\t},\n\n\t_slide: function( event, index, newVal ) {\n\t\tvar otherVal,\n\t\t\tnewValues,\n\t\t\tallowed;\n\n\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\totherVal = this.values( index ? 0 : 1 );\n\n\t\t\tif ( ( this.options.values.length === 2 && this.options.range === true ) && \n\t\t\t\t\t( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )\n\t\t\t\t) {\n\t\t\t\tnewVal = otherVal;\n\t\t\t}\n\n\t\t\tif ( newVal !== this.values( index ) ) {\n\t\t\t\tnewValues = this.values();\n\t\t\t\tnewValues[ index ] = newVal;\n\t\t\t\t// A slide can be canceled by returning false from the slide callback\n\t\t\t\tallowed = this._trigger( \"slide\", event, {\n\t\t\t\t\thandle: this.handles[ index ],\n\t\t\t\t\tvalue: newVal,\n\t\t\t\t\tvalues: newValues\n\t\t\t\t} );\n\t\t\t\totherVal = this.values( index ? 0 : 1 );\n\t\t\t\tif ( allowed !== false ) {\n\t\t\t\t\tthis.values( index, newVal, true );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif ( newVal !== this.value() ) {\n\t\t\t\t// A slide can be canceled by returning false from the slide callback\n\t\t\t\tallowed = this._trigger( \"slide\", event, {\n\t\t\t\t\thandle: this.handles[ index ],\n\t\t\t\t\tvalue: newVal\n\t\t\t\t} );\n\t\t\t\tif ( allowed !== false ) {\n\t\t\t\t\tthis.value( newVal );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t_stop: function( event, index ) {\n\t\tvar uiHash = {\n\t\t\thandle: this.handles[ index ],\n\t\t\tvalue: this.value()\n\t\t};\n\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\tuiHash.value = this.values( index );\n\t\t\tuiHash.values = this.values();\n\t\t}\n\n\t\tthis._trigger( \"stop\", event, uiHash );\n\t},\n\n\t_change: function( event, index ) {\n\t\tif ( !this._keySliding && !this._mouseSliding ) {\n\t\t\tvar uiHash = {\n\t\t\t\thandle: this.handles[ index ],\n\t\t\t\tvalue: this.value()\n\t\t\t};\n\t\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\t\tuiHash.value = this.values( index );\n\t\t\t\tuiHash.values = this.values();\n\t\t\t}\n\n\t\t\tthis._trigger( \"change\", event, uiHash );\n\t\t}\n\t},\n\n\tvalue: function( newValue ) {\n\t\tif ( arguments.length ) {\n\t\t\tthis.options.value = this._trimAlignValue( newValue );\n\t\t\tthis._refreshValue();\n\t\t\tthis._change( null, 0 );\n\t\t}\n\n\t\treturn this._value();\n\t},\n\n\tvalues: function( index, newValue ) {\n\t\tvar vals,\n\t\t\tnewValues,\n\t\t\ti;\n\n\t\tif ( arguments.length > 1 ) {\n\t\t\tthis.options.values[ index ] = this._trimAlignValue( newValue );\n\t\t\tthis._refreshValue();\n\t\t\tthis._change( null, index );\n\t\t}\n\n\t\tif ( arguments.length ) {\n\t\t\tif ( $.isArray( arguments[ 0 ] ) ) {\n\t\t\t\tvals = this.options.values;\n\t\t\t\tnewValues = arguments[ 0 ];\n\t\t\t\tfor ( i = 0; i < vals.length; i += 1 ) {\n\t\t\t\t\tvals[ i ] = this._trimAlignValue( newValues[ i ] );\n\t\t\t\t\tthis._change( null, i );\n\t\t\t\t}\n\t\t\t\tthis._refreshValue();\n\t\t\t} else {\n\t\t\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\t\t\treturn this._values( index );\n\t\t\t\t} else {\n\t\t\t\t\treturn this.value();\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\treturn this._values();\n\t\t}\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tvar i,\n\t\t\tvalsLength = 0;\n\n\t\tif ( $.isArray( this.options.values ) ) {\n\t\t\tvalsLength = this.options.values.length;\n\t\t}\n\n\t\t$.Widget.prototype._setOption.apply( this, arguments );\n\n\t\tswitch ( key ) {\n\t\t\tcase \"disabled\":\n\t\t\t\tif ( value ) {\n\t\t\t\t\tthis.handles.filter( \".ui-state-focus\" ).blur();\n\t\t\t\t\tthis.handles.removeClass( \"ui-state-hover\" );\n\t\t\t\t\tthis.handles.attr( \"disabled\", \"disabled\" );\n\t\t\t\t\tthis.element.addClass( \"ui-disabled\" );\n\t\t\t\t} else {\n\t\t\t\t\tthis.handles.removeAttr( \"disabled\" );\n\t\t\t\t\tthis.element.removeClass( \"ui-disabled\" );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"orientation\":\n\t\t\t\tthis._detectOrientation();\n\t\t\t\tthis.element\n\t\t\t\t\t.removeClass( \"ui-slider-horizontal ui-slider-vertical\" )\n\t\t\t\t\t.addClass( \"ui-slider-\" + this.orientation );\n\t\t\t\tthis._refreshValue();\n\t\t\t\tbreak;\n\t\t\tcase \"value\":\n\t\t\t\tthis._animateOff = true;\n\t\t\t\tthis._refreshValue();\n\t\t\t\tthis._change( null, 0 );\n\t\t\t\tthis._animateOff = false;\n\t\t\t\tbreak;\n\t\t\tcase \"values\":\n\t\t\t\tthis._animateOff = true;\n\t\t\t\tthis._refreshValue();\n\t\t\t\tfor ( i = 0; i < valsLength; i += 1 ) {\n\t\t\t\t\tthis._change( null, i );\n\t\t\t\t}\n\t\t\t\tthis._animateOff = false;\n\t\t\t\tbreak;\n\t\t}\n\t},\n\n\t//internal value getter\n\t// _value() returns value trimmed by min and max, aligned by step\n\t_value: function() {\n\t\tvar val = this.options.value;\n\t\tval = this._trimAlignValue( val );\n\n\t\treturn val;\n\t},\n\n\t//internal values getter\n\t// _values() returns array of values trimmed by min and max, aligned by step\n\t// _values( index ) returns single value trimmed by min and max, aligned by step\n\t_values: function( index ) {\n\t\tvar val,\n\t\t\tvals,\n\t\t\ti;\n\n\t\tif ( arguments.length ) {\n\t\t\tval = this.options.values[ index ];\n\t\t\tval = this._trimAlignValue( val );\n\n\t\t\treturn val;\n\t\t} else {\n\t\t\t// .slice() creates a copy of the array\n\t\t\t// this copy gets trimmed by min and max and then returned\n\t\t\tvals = this.options.values.slice();\n\t\t\tfor ( i = 0; i < vals.length; i+= 1) {\n\t\t\t\tvals[ i ] = this._trimAlignValue( vals[ i ] );\n\t\t\t}\n\n\t\t\treturn vals;\n\t\t}\n\t},\n\t\n\t// returns the step-aligned value that val is closest to, between (inclusive) min and max\n\t_trimAlignValue: function( val ) {\n\t\tif ( val < this._valueMin() ) {\n\t\t\treturn this._valueMin();\n\t\t}\n\t\tif ( val > this._valueMax() ) {\n\t\t\treturn this._valueMax();\n\t\t}\n\t\tvar step = ( this.options.step > 0 ) ? this.options.step : 1,\n\t\t\tvalModStep = val % step,\n\t\t\talignValue = val - valModStep;\n\n\t\tif ( Math.abs(valModStep) * 2 >= step ) {\n\t\t\talignValue += ( valModStep > 0 ) ? step : ( -step );\n\t\t}\n\n\t\t// Since JavaScript has problems with large floats, round\n\t\t// the final value to 5 digits after the decimal point (see #4124)\n\t\treturn parseFloat( alignValue.toFixed(5) );\n\t},\n\n\t_valueMin: function() {\n\t\treturn this.options.min;\n\t},\n\n\t_valueMax: function() {\n\t\treturn this.options.max;\n\t},\n\t\n\t_refreshValue: function() {\n\t\tvar oRange = this.options.range,\n\t\t\to = this.options,\n\t\t\tself = this,\n\t\t\tanimate = ( !this._animateOff ) ? o.animate : false,\n\t\t\tvalPercent,\n\t\t\t_set = {},\n\t\t\tlastValPercent,\n\t\t\tvalue,\n\t\t\tvalueMin,\n\t\t\tvalueMax;\n\n\t\tif ( this.options.values && this.options.values.length ) {\n\t\t\tthis.handles.each(function( i, j ) {\n\t\t\t\tvalPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100;\n\t\t\t\t_set[ self.orientation === \"horizontal\" ? \"left\" : \"bottom\" ] = valPercent + \"%\";\n\t\t\t\t$( this ).stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( _set, o.animate );\n\t\t\t\tif ( self.options.range === true ) {\n\t\t\t\t\tif ( self.orientation === \"horizontal\" ) {\n\t\t\t\t\t\tif ( i === 0 ) {\n\t\t\t\t\t\t\tself.range.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( { left: valPercent + \"%\" }, o.animate );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( i === 1 ) {\n\t\t\t\t\t\t\tself.range[ animate ? \"animate\" : \"css\" ]( { width: ( valPercent - lastValPercent ) + \"%\" }, { queue: false, duration: o.animate } );\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( i === 0 ) {\n\t\t\t\t\t\t\tself.range.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( { bottom: ( valPercent ) + \"%\" }, o.animate );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( i === 1 ) {\n\t\t\t\t\t\t\tself.range[ animate ? \"animate\" : \"css\" ]( { height: ( valPercent - lastValPercent ) + \"%\" }, { queue: false, duration: o.animate } );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlastValPercent = valPercent;\n\t\t\t});\n\t\t} else {\n\t\t\tvalue = this.value();\n\t\t\tvalueMin = this._valueMin();\n\t\t\tvalueMax = this._valueMax();\n\t\t\tvalPercent = ( valueMax !== valueMin ) ?\n\t\t\t\t\t( value - valueMin ) / ( valueMax - valueMin ) * 100 :\n\t\t\t\t\t0;\n\t\t\t_set[ self.orientation === \"horizontal\" ? \"left\" : \"bottom\" ] = valPercent + \"%\";\n\t\t\tthis.handle.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( _set, o.animate );\n\n\t\t\tif ( oRange === \"min\" && this.orientation === \"horizontal\" ) {\n\t\t\t\tthis.range.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( { width: valPercent + \"%\" }, o.animate );\n\t\t\t}\n\t\t\tif ( oRange === \"max\" && this.orientation === \"horizontal\" ) {\n\t\t\t\tthis.range[ animate ? \"animate\" : \"css\" ]( { width: ( 100 - valPercent ) + \"%\" }, { queue: false, duration: o.animate } );\n\t\t\t}\n\t\t\tif ( oRange === \"min\" && this.orientation === \"vertical\" ) {\n\t\t\t\tthis.range.stop( 1, 1 )[ animate ? \"animate\" : \"css\" ]( { height: valPercent + \"%\" }, o.animate );\n\t\t\t}\n\t\t\tif ( oRange === \"max\" && this.orientation === \"vertical\" ) {\n\t\t\t\tthis.range[ animate ? \"animate\" : \"css\" ]( { height: ( 100 - valPercent ) + \"%\" }, { queue: false, duration: o.animate } );\n\t\t\t}\n\t\t}\n\t}\n\n});\n\n$.extend( $.ui.slider, {\n\tversion: \"1.8.6\"\n});\n\n}(jQuery));\n/*\n * jQuery UI Tabs 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Tabs\n *\n * Depends:\n *\tjquery.ui.core.js\n *\tjquery.ui.widget.js\n */\n(function( $, undefined ) {\n\nvar tabId = 0,\n\tlistId = 0;\n\nfunction getNextTabId() {\n\treturn ++tabId;\n}\n\nfunction getNextListId() {\n\treturn ++listId;\n}\n\n$.widget( \"ui.tabs\", {\n\toptions: {\n\t\tadd: null,\n\t\tajaxOptions: null,\n\t\tcache: false,\n\t\tcookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }\n\t\tcollapsible: false,\n\t\tdisable: null,\n\t\tdisabled: [],\n\t\tenable: null,\n\t\tevent: \"click\",\n\t\tfx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }\n\t\tidPrefix: \"ui-tabs-\",\n\t\tload: null,\n\t\tpanelTemplate: \"<div></div>\",\n\t\tremove: null,\n\t\tselect: null,\n\t\tshow: null,\n\t\tspinner: \"<em>Loading&#8230;</em>\",\n\t\ttabTemplate: \"<li><a href='#{href}'><span>#{label}</span></a></li>\"\n\t},\n\n\t_create: function() {\n\t\tthis._tabify( true );\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key == \"selected\" ) {\n\t\t\tif (this.options.collapsible && value == this.options.selected ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.select( value );\n\t\t} else {\n\t\t\tthis.options[ key ] = value;\n\t\t\tthis._tabify();\n\t\t}\n\t},\n\n\t_tabId: function( a ) {\n\t\treturn a.title && a.title.replace( /\\s/g, \"_\" ).replace( /[^\\w\\u00c0-\\uFFFF-]/g, \"\" ) ||\n\t\t\tthis.options.idPrefix + getNextTabId();\n\t},\n\n\t_sanitizeSelector: function( hash ) {\n\t\t// we need this because an id may contain a \":\"\n\t\treturn hash.replace( /:/g, \"\\\\:\" );\n\t},\n\n\t_cookie: function() {\n\t\tvar cookie = this.cookie ||\n\t\t\t( this.cookie = this.options.cookie.name || \"ui-tabs-\" + getNextListId() );\n\t\treturn $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) );\n\t},\n\n\t_ui: function( tab, panel ) {\n\t\treturn {\n\t\t\ttab: tab,\n\t\t\tpanel: panel,\n\t\t\tindex: this.anchors.index( tab )\n\t\t};\n\t},\n\n\t_cleanup: function() {\n\t\t// restore all former loading tabs labels\n\t\tthis.lis.filter( \".ui-state-processing\" )\n\t\t\t.removeClass( \"ui-state-processing\" )\n\t\t\t.find( \"span:data(label.tabs)\" )\n\t\t\t\t.each(function() {\n\t\t\t\t\tvar el = $( this );\n\t\t\t\t\tel.html( el.data( \"label.tabs\" ) ).removeData( \"label.tabs\" );\n\t\t\t\t});\n\t},\n\n\t_tabify: function( init ) {\n\t\tvar self = this,\n\t\t\to = this.options,\n\t\t\tfragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash\n\n\t\tthis.list = this.element.find( \"ol,ul\" ).eq( 0 );\n\t\tthis.lis = $( \" > li:has(a[href])\", this.list );\n\t\tthis.anchors = this.lis.map(function() {\n\t\t\treturn $( \"a\", this )[ 0 ];\n\t\t});\n\t\tthis.panels = $( [] );\n\n\t\tthis.anchors.each(function( i, a ) {\n\t\t\tvar href = $( a ).attr( \"href\" );\n\t\t\t// For dynamically created HTML that contains a hash as href IE < 8 expands\n\t\t\t// such href to the full page url with hash and then misinterprets tab as ajax.\n\t\t\t// Same consideration applies for an added tab with a fragment identifier\n\t\t\t// since a[href=#fragment-identifier] does unexpectedly not match.\n\t\t\t// Thus normalize href attribute...\n\t\t\tvar hrefBase = href.split( \"#\" )[ 0 ],\n\t\t\t\tbaseEl;\n\t\t\tif ( hrefBase && ( hrefBase === location.toString().split( \"#\" )[ 0 ] ||\n\t\t\t\t\t( baseEl = $( \"base\" )[ 0 ]) && hrefBase === baseEl.href ) ) {\n\t\t\t\thref = a.hash;\n\t\t\t\ta.href = href;\n\t\t\t}\n\n\t\t\t// inline tab\n\t\t\tif ( fragmentId.test( href ) ) {\n\t\t\t\tself.panels = self.panels.add( self._sanitizeSelector( href ) );\n\t\t\t// remote tab\n\t\t\t// prevent loading the page itself if href is just \"#\"\n\t\t\t} else if ( href && href !== \"#\" ) {\n\t\t\t\t// required for restore on destroy\n\t\t\t\t$.data( a, \"href.tabs\", href );\n\n\t\t\t\t// TODO until #3808 is fixed strip fragment identifier from url\n\t\t\t\t// (IE fails to load from such url)\n\t\t\t\t$.data( a, \"load.tabs\", href.replace( /#.*$/, \"\" ) );\n\n\t\t\t\tvar id = self._tabId( a );\n\t\t\t\ta.href = \"#\" + id;\n\t\t\t\tvar $panel = $( \"#\" + id );\n\t\t\t\tif ( !$panel.length ) {\n\t\t\t\t\t$panel = $( o.panelTemplate )\n\t\t\t\t\t\t.attr( \"id\", id )\n\t\t\t\t\t\t.addClass( \"ui-tabs-panel ui-widget-content ui-corner-bottom\" )\n\t\t\t\t\t\t.insertAfter( self.panels[ i - 1 ] || self.list );\n\t\t\t\t\t$panel.data( \"destroy.tabs\", true );\n\t\t\t\t}\n\t\t\t\tself.panels = self.panels.add( $panel );\n\t\t\t// invalid tab href\n\t\t\t} else {\n\t\t\t\to.disabled.push( i );\n\t\t\t}\n\t\t});\n\n\t\t// initialization from scratch\n\t\tif ( init ) {\n\t\t\t// attach necessary classes for styling\n\t\t\tthis.element.addClass( \"ui-tabs ui-widget ui-widget-content ui-corner-all\" );\n\t\t\tthis.list.addClass( \"ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all\" );\n\t\t\tthis.lis.addClass( \"ui-state-default ui-corner-top\" );\n\t\t\tthis.panels.addClass( \"ui-tabs-panel ui-widget-content ui-corner-bottom\" );\n\n\t\t\t// Selected tab\n\t\t\t// use \"selected\" option or try to retrieve:\n\t\t\t// 1. from fragment identifier in url\n\t\t\t// 2. from cookie\n\t\t\t// 3. from selected class attribute on <li>\n\t\t\tif ( o.selected === undefined ) {\n\t\t\t\tif ( location.hash ) {\n\t\t\t\t\tthis.anchors.each(function( i, a ) {\n\t\t\t\t\t\tif ( a.hash == location.hash ) {\n\t\t\t\t\t\t\to.selected = i;\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}\n\t\t\t\tif ( typeof o.selected !== \"number\" && o.cookie ) {\n\t\t\t\t\to.selected = parseInt( self._cookie(), 10 );\n\t\t\t\t}\n\t\t\t\tif ( typeof o.selected !== \"number\" && this.lis.filter( \".ui-tabs-selected\" ).length ) {\n\t\t\t\t\to.selected = this.lis.index( this.lis.filter( \".ui-tabs-selected\" ) );\n\t\t\t\t}\n\t\t\t\to.selected = o.selected || ( this.lis.length ? 0 : -1 );\n\t\t\t} else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release\n\t\t\t\to.selected = -1;\n\t\t\t}\n\n\t\t\t// sanity check - default to first tab...\n\t\t\to.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 )\n\t\t\t\t? o.selected\n\t\t\t\t: 0;\n\n\t\t\t// Take disabling tabs via class attribute from HTML\n\t\t\t// into account and update option properly.\n\t\t\t// A selected tab cannot become disabled.\n\t\t\to.disabled = $.unique( o.disabled.concat(\n\t\t\t\t$.map( this.lis.filter( \".ui-state-disabled\" ), function( n, i ) {\n\t\t\t\t\treturn self.lis.index( n );\n\t\t\t\t})\n\t\t\t) ).sort();\n\n\t\t\tif ( $.inArray( o.selected, o.disabled ) != -1 ) {\n\t\t\t\to.disabled.splice( $.inArray( o.selected, o.disabled ), 1 );\n\t\t\t}\n\n\t\t\t// highlight selected tab\n\t\t\tthis.panels.addClass( \"ui-tabs-hide\" );\n\t\t\tthis.lis.removeClass( \"ui-tabs-selected ui-state-active\" );\n\t\t\t// check for length avoids error when initializing empty list\n\t\t\tif ( o.selected >= 0 && this.anchors.length ) {\n\t\t\t\t$( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( \"ui-tabs-hide\" );\n\t\t\t\tthis.lis.eq( o.selected ).addClass( \"ui-tabs-selected ui-state-active\" );\n\n\t\t\t\t// seems to be expected behavior that the show callback is fired\n\t\t\t\tself.element.queue( \"tabs\", function() {\n\t\t\t\t\tself._trigger( \"show\", null,\n\t\t\t\t\t\tself._ui( self.anchors[ o.selected ], $( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ) ) );\n\t\t\t\t});\n\n\t\t\t\tthis.load( o.selected );\n\t\t\t}\n\n\t\t\t// clean up to avoid memory leaks in certain versions of IE 6\n\t\t\t// TODO: namespace this event\n\t\t\t$( window ).bind( \"unload\", function() {\n\t\t\t\tself.lis.add( self.anchors ).unbind( \".tabs\" );\n\t\t\t\tself.lis = self.anchors = self.panels = null;\n\t\t\t});\n\t\t// update selected after add/remove\n\t\t} else {\n\t\t\to.selected = this.lis.index( this.lis.filter( \".ui-tabs-selected\" ) );\n\t\t}\n\n\t\t// update collapsible\n\t\t// TODO: use .toggleClass()\n\t\tthis.element[ o.collapsible ? \"addClass\" : \"removeClass\" ]( \"ui-tabs-collapsible\" );\n\n\t\t// set or update cookie after init and add/remove respectively\n\t\tif ( o.cookie ) {\n\t\t\tthis._cookie( o.selected, o.cookie );\n\t\t}\n\n\t\t// disable tabs\n\t\tfor ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) {\n\t\t\t$( li )[ $.inArray( i, o.disabled ) != -1 &&\n\t\t\t\t// TODO: use .toggleClass()\n\t\t\t\t!$( li ).hasClass( \"ui-tabs-selected\" ) ? \"addClass\" : \"removeClass\" ]( \"ui-state-disabled\" );\n\t\t}\n\n\t\t// reset cache if switching from cached to not cached\n\t\tif ( o.cache === false ) {\n\t\t\tthis.anchors.removeData( \"cache.tabs\" );\n\t\t}\n\n\t\t// remove all handlers before, tabify may run on existing tabs after add or option change\n\t\tthis.lis.add( this.anchors ).unbind( \".tabs\" );\n\n\t\tif ( o.event !== \"mouseover\" ) {\n\t\t\tvar addState = function( state, el ) {\n\t\t\t\tif ( el.is( \":not(.ui-state-disabled)\" ) ) {\n\t\t\t\t\tel.addClass( \"ui-state-\" + state );\n\t\t\t\t}\n\t\t\t};\n\t\t\tvar removeState = function( state, el ) {\n\t\t\t\tel.removeClass( \"ui-state-\" + state );\n\t\t\t};\n\t\t\tthis.lis.bind( \"mouseover.tabs\" , function() {\n\t\t\t\taddState( \"hover\", $( this ) );\n\t\t\t});\n\t\t\tthis.lis.bind( \"mouseout.tabs\", function() {\n\t\t\t\tremoveState( \"hover\", $( this ) );\n\t\t\t});\n\t\t\tthis.anchors.bind( \"focus.tabs\", function() {\n\t\t\t\taddState( \"focus\", $( this ).closest( \"li\" ) );\n\t\t\t});\n\t\t\tthis.anchors.bind( \"blur.tabs\", function() {\n\t\t\t\tremoveState( \"focus\", $( this ).closest( \"li\" ) );\n\t\t\t});\n\t\t}\n\n\t\t// set up animations\n\t\tvar hideFx, showFx;\n\t\tif ( o.fx ) {\n\t\t\tif ( $.isArray( o.fx ) ) {\n\t\t\t\thideFx = o.fx[ 0 ];\n\t\t\t\tshowFx = o.fx[ 1 ];\n\t\t\t} else {\n\t\t\t\thideFx = showFx = o.fx;\n\t\t\t}\n\t\t}\n\n\t\t// Reset certain styles left over from animation\n\t\t// and prevent IE's ClearType bug...\n\t\tfunction resetStyle( $el, fx ) {\n\t\t\t$el.css( \"display\", \"\" );\n\t\t\tif ( !$.support.opacity && fx.opacity ) {\n\t\t\t\t$el[ 0 ].style.removeAttribute( \"filter\" );\n\t\t\t}\n\t\t}\n\n\t\t// Show a tab...\n\t\tvar showTab = showFx\n\t\t\t? function( clicked, $show ) {\n\t\t\t\t$( clicked ).closest( \"li\" ).addClass( \"ui-tabs-selected ui-state-active\" );\n\t\t\t\t$show.hide().removeClass( \"ui-tabs-hide\" ) // avoid flicker that way\n\t\t\t\t\t.animate( showFx, showFx.duration || \"normal\", function() {\n\t\t\t\t\t\tresetStyle( $show, showFx );\n\t\t\t\t\t\tself._trigger( \"show\", null, self._ui( clicked, $show[ 0 ] ) );\n\t\t\t\t\t});\n\t\t\t}\n\t\t\t: function( clicked, $show ) {\n\t\t\t\t$( clicked ).closest( \"li\" ).addClass( \"ui-tabs-selected ui-state-active\" );\n\t\t\t\t$show.removeClass( \"ui-tabs-hide\" );\n\t\t\t\tself._trigger( \"show\", null, self._ui( clicked, $show[ 0 ] ) );\n\t\t\t};\n\n\t\t// Hide a tab, $show is optional...\n\t\tvar hideTab = hideFx\n\t\t\t? function( clicked, $hide ) {\n\t\t\t\t$hide.animate( hideFx, hideFx.duration || \"normal\", function() {\n\t\t\t\t\tself.lis.removeClass( \"ui-tabs-selected ui-state-active\" );\n\t\t\t\t\t$hide.addClass( \"ui-tabs-hide\" );\n\t\t\t\t\tresetStyle( $hide, hideFx );\n\t\t\t\t\tself.element.dequeue( \"tabs\" );\n\t\t\t\t});\n\t\t\t}\n\t\t\t: function( clicked, $hide, $show ) {\n\t\t\t\tself.lis.removeClass( \"ui-tabs-selected ui-state-active\" );\n\t\t\t\t$hide.addClass( \"ui-tabs-hide\" );\n\t\t\t\tself.element.dequeue( \"tabs\" );\n\t\t\t};\n\n\t\t// attach tab event handler, unbind to avoid duplicates from former tabifying...\n\t\tthis.anchors.bind( o.event + \".tabs\", function() {\n\t\t\tvar el = this,\n\t\t\t\t$li = $(el).closest( \"li\" ),\n\t\t\t\t$hide = self.panels.filter( \":not(.ui-tabs-hide)\" ),\n\t\t\t\t$show = $( self._sanitizeSelector( el.hash ) );\n\n\t\t\t// If tab is already selected and not collapsible or tab disabled or\n\t\t\t// or is already loading or click callback returns false stop here.\n\t\t\t// Check if click handler returns false last so that it is not executed\n\t\t\t// for a disabled or loading tab!\n\t\t\tif ( ( $li.hasClass( \"ui-tabs-selected\" ) && !o.collapsible) ||\n\t\t\t\t$li.hasClass( \"ui-state-disabled\" ) ||\n\t\t\t\t$li.hasClass( \"ui-state-processing\" ) ||\n\t\t\t\tself.panels.filter( \":animated\" ).length ||\n\t\t\t\tself._trigger( \"select\", null, self._ui( this, $show[ 0 ] ) ) === false ) {\n\t\t\t\tthis.blur();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\to.selected = self.anchors.index( this );\n\n\t\t\tself.abort();\n\n\t\t\t// if tab may be closed\n\t\t\tif ( o.collapsible ) {\n\t\t\t\tif ( $li.hasClass( \"ui-tabs-selected\" ) ) {\n\t\t\t\t\to.selected = -1;\n\n\t\t\t\t\tif ( o.cookie ) {\n\t\t\t\t\t\tself._cookie( o.selected, o.cookie );\n\t\t\t\t\t}\n\n\t\t\t\t\tself.element.queue( \"tabs\", function() {\n\t\t\t\t\t\thideTab( el, $hide );\n\t\t\t\t\t}).dequeue( \"tabs\" );\n\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t} else if ( !$hide.length ) {\n\t\t\t\t\tif ( o.cookie ) {\n\t\t\t\t\t\tself._cookie( o.selected, o.cookie );\n\t\t\t\t\t}\n\n\t\t\t\t\tself.element.queue( \"tabs\", function() {\n\t\t\t\t\t\tshowTab( el, $show );\n\t\t\t\t\t});\n\n\t\t\t\t\t// TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171\n\t\t\t\t\tself.load( self.anchors.index( this ) );\n\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( o.cookie ) {\n\t\t\t\tself._cookie( o.selected, o.cookie );\n\t\t\t}\n\n\t\t\t// show new tab\n\t\t\tif ( $show.length ) {\n\t\t\t\tif ( $hide.length ) {\n\t\t\t\t\tself.element.queue( \"tabs\", function() {\n\t\t\t\t\t\thideTab( el, $hide );\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tself.element.queue( \"tabs\", function() {\n\t\t\t\t\tshowTab( el, $show );\n\t\t\t\t});\n\n\t\t\t\tself.load( self.anchors.index( this ) );\n\t\t\t} else {\n\t\t\t\tthrow \"jQuery UI Tabs: Mismatching fragment identifier.\";\n\t\t\t}\n\n\t\t\t// Prevent IE from keeping other link focussed when using the back button\n\t\t\t// and remove dotted border from clicked link. This is controlled via CSS\n\t\t\t// in modern browsers; blur() removes focus from address bar in Firefox\n\t\t\t// which can become a usability and annoying problem with tabs('rotate').\n\t\t\tif ( $.browser.msie ) {\n\t\t\t\tthis.blur();\n\t\t\t}\n\t\t});\n\n\t\t// disable click in any case\n\t\tthis.anchors.bind( \"click.tabs\", function(){\n\t\t\treturn false;\n\t\t});\n\t},\n\n    _getIndex: function( index ) {\n\t\t// meta-function to give users option to provide a href string instead of a numerical index.\n\t\t// also sanitizes numerical indexes to valid values.\n\t\tif ( typeof index == \"string\" ) {\n\t\t\tindex = this.anchors.index( this.anchors.filter( \"[href$=\" + index + \"]\" ) );\n\t\t}\n\n\t\treturn index;\n\t},\n\n\tdestroy: function() {\n\t\tvar o = this.options;\n\n\t\tthis.abort();\n\n\t\tthis.element\n\t\t\t.unbind( \".tabs\" )\n\t\t\t.removeClass( \"ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible\" )\n\t\t\t.removeData( \"tabs\" );\n\n\t\tthis.list.removeClass( \"ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all\" );\n\n\t\tthis.anchors.each(function() {\n\t\t\tvar href = $.data( this, \"href.tabs\" );\n\t\t\tif ( href ) {\n\t\t\t\tthis.href = href;\n\t\t\t}\n\t\t\tvar $this = $( this ).unbind( \".tabs\" );\n\t\t\t$.each( [ \"href\", \"load\", \"cache\" ], function( i, prefix ) {\n\t\t\t\t$this.removeData( prefix + \".tabs\" );\n\t\t\t});\n\t\t});\n\n\t\tthis.lis.unbind( \".tabs\" ).add( this.panels ).each(function() {\n\t\t\tif ( $.data( this, \"destroy.tabs\" ) ) {\n\t\t\t\t$( this ).remove();\n\t\t\t} else {\n\t\t\t\t$( this ).removeClass([\n\t\t\t\t\t\"ui-state-default\",\n\t\t\t\t\t\"ui-corner-top\",\n\t\t\t\t\t\"ui-tabs-selected\",\n\t\t\t\t\t\"ui-state-active\",\n\t\t\t\t\t\"ui-state-hover\",\n\t\t\t\t\t\"ui-state-focus\",\n\t\t\t\t\t\"ui-state-disabled\",\n\t\t\t\t\t\"ui-tabs-panel\",\n\t\t\t\t\t\"ui-widget-content\",\n\t\t\t\t\t\"ui-corner-bottom\",\n\t\t\t\t\t\"ui-tabs-hide\"\n\t\t\t\t].join( \" \" ) );\n\t\t\t}\n\t\t});\n\n\t\tif ( o.cookie ) {\n\t\t\tthis._cookie( null, o.cookie );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tadd: function( url, label, index ) {\n\t\tif ( index === undefined ) {\n\t\t\tindex = this.anchors.length;\n\t\t}\n\n\t\tvar self = this,\n\t\t\to = this.options,\n\t\t\t$li = $( o.tabTemplate.replace( /#\\{href\\}/g, url ).replace( /#\\{label\\}/g, label ) ),\n\t\t\tid = !url.indexOf( \"#\" ) ? url.replace( \"#\", \"\" ) : this._tabId( $( \"a\", $li )[ 0 ] );\n\n\t\t$li.addClass( \"ui-state-default ui-corner-top\" ).data( \"destroy.tabs\", true );\n\n\t\t// try to find an existing element before creating a new one\n\t\tvar $panel = $( \"#\" + id );\n\t\tif ( !$panel.length ) {\n\t\t\t$panel = $( o.panelTemplate )\n\t\t\t\t.attr( \"id\", id )\n\t\t\t\t.data( \"destroy.tabs\", true );\n\t\t}\n\t\t$panel.addClass( \"ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide\" );\n\n\t\tif ( index >= this.lis.length ) {\n\t\t\t$li.appendTo( this.list );\n\t\t\t$panel.appendTo( this.list[ 0 ].parentNode );\n\t\t} else {\n\t\t\t$li.insertBefore( this.lis[ index ] );\n\t\t\t$panel.insertBefore( this.panels[ index ] );\n\t\t}\n\n\t\to.disabled = $.map( o.disabled, function( n, i ) {\n\t\t\treturn n >= index ? ++n : n;\n\t\t});\n\n\t\tthis._tabify();\n\n\t\tif ( this.anchors.length == 1 ) {\n\t\t\to.selected = 0;\n\t\t\t$li.addClass( \"ui-tabs-selected ui-state-active\" );\n\t\t\t$panel.removeClass( \"ui-tabs-hide\" );\n\t\t\tthis.element.queue( \"tabs\", function() {\n\t\t\t\tself._trigger( \"show\", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) );\n\t\t\t});\n\n\t\t\tthis.load( 0 );\n\t\t}\n\n\t\tthis._trigger( \"add\", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );\n\t\treturn this;\n\t},\n\n\tremove: function( index ) {\n\t\tindex = this._getIndex( index );\n\t\tvar o = this.options,\n\t\t\t$li = this.lis.eq( index ).remove(),\n\t\t\t$panel = this.panels.eq( index ).remove();\n\n\t\t// If selected tab was removed focus tab to the right or\n\t\t// in case the last tab was removed the tab to the left.\n\t\tif ( $li.hasClass( \"ui-tabs-selected\" ) && this.anchors.length > 1) {\n\t\t\tthis.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );\n\t\t}\n\n\t\to.disabled = $.map(\n\t\t\t$.grep( o.disabled, function(n, i) {\n\t\t\t\treturn n != index;\n\t\t\t}),\n\t\t\tfunction( n, i ) {\n\t\t\t\treturn n >= index ? --n : n;\n\t\t\t});\n\n\t\tthis._tabify();\n\n\t\tthis._trigger( \"remove\", null, this._ui( $li.find( \"a\" )[ 0 ], $panel[ 0 ] ) );\n\t\treturn this;\n\t},\n\n\tenable: function( index ) {\n\t\tindex = this._getIndex( index );\n\t\tvar o = this.options;\n\t\tif ( $.inArray( index, o.disabled ) == -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lis.eq( index ).removeClass( \"ui-state-disabled\" );\n\t\to.disabled = $.grep( o.disabled, function( n, i ) {\n\t\t\treturn n != index;\n\t\t});\n\n\t\tthis._trigger( \"enable\", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );\n\t\treturn this;\n\t},\n\n\tdisable: function( index ) {\n\t\tindex = this._getIndex( index );\n\t\tvar self = this, o = this.options;\n\t\t// cannot disable already selected tab\n\t\tif ( index != o.selected ) {\n\t\t\tthis.lis.eq( index ).addClass( \"ui-state-disabled\" );\n\n\t\t\to.disabled.push( index );\n\t\t\to.disabled.sort();\n\n\t\t\tthis._trigger( \"disable\", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tselect: function( index ) {\n\t\tindex = this._getIndex( index );\n\t\tif ( index == -1 ) {\n\t\t\tif ( this.options.collapsible && this.options.selected != -1 ) {\n\t\t\t\tindex = this.options.selected;\n\t\t\t} else {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t}\n\t\tthis.anchors.eq( index ).trigger( this.options.event + \".tabs\" );\n\t\treturn this;\n\t},\n\n\tload: function( index ) {\n\t\tindex = this._getIndex( index );\n\t\tvar self = this,\n\t\t\to = this.options,\n\t\t\ta = this.anchors.eq( index )[ 0 ],\n\t\t\turl = $.data( a, \"load.tabs\" );\n\n\t\tthis.abort();\n\n\t\t// not remote or from cache\n\t\tif ( !url || this.element.queue( \"tabs\" ).length !== 0 && $.data( a, \"cache.tabs\" ) ) {\n\t\t\tthis.element.dequeue( \"tabs\" );\n\t\t\treturn;\n\t\t}\n\n\t\t// load remote from here on\n\t\tthis.lis.eq( index ).addClass( \"ui-state-processing\" );\n\n\t\tif ( o.spinner ) {\n\t\t\tvar span = $( \"span\", a );\n\t\t\tspan.data( \"label.tabs\", span.html() ).html( o.spinner );\n\t\t}\n\n\t\tthis.xhr = $.ajax( $.extend( {}, o.ajaxOptions, {\n\t\t\turl: url,\n\t\t\tsuccess: function( r, s ) {\n\t\t\t\t$( self._sanitizeSelector( a.hash ) ).html( r );\n\n\t\t\t\t// take care of tab labels\n\t\t\t\tself._cleanup();\n\n\t\t\t\tif ( o.cache ) {\n\t\t\t\t\t$.data( a, \"cache.tabs\", true );\n\t\t\t\t}\n\n\t\t\t\tself._trigger( \"load\", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );\n\t\t\t\ttry {\n\t\t\t\t\to.ajaxOptions.success( r, s );\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t},\n\t\t\terror: function( xhr, s, e ) {\n\t\t\t\t// take care of tab labels\n\t\t\t\tself._cleanup();\n\n\t\t\t\tself._trigger( \"load\", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );\n\t\t\t\ttry {\n\t\t\t\t\t// Passing index avoid a race condition when this method is\n\t\t\t\t\t// called after the user has selected another tab.\n\t\t\t\t\t// Pass the anchor that initiated this request allows\n\t\t\t\t\t// loadError to manipulate the tab content panel via $(a.hash)\n\t\t\t\t\to.ajaxOptions.error( xhr, s, index, a );\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} ) );\n\n\t\t// last, so that load event is fired before show...\n\t\tself.element.dequeue( \"tabs\" );\n\n\t\treturn this;\n\t},\n\n\tabort: function() {\n\t\t// stop possibly running animations\n\t\tthis.element.queue( [] );\n\t\tthis.panels.stop( false, true );\n\n\t\t// \"tabs\" queue must not contain more than two elements,\n\t\t// which are the callbacks for the latest clicked tab...\n\t\tthis.element.queue( \"tabs\", this.element.queue( \"tabs\" ).splice( -2, 2 ) );\n\n\t\t// terminate pending requests from other tabs\n\t\tif ( this.xhr ) {\n\t\t\tthis.xhr.abort();\n\t\t\tdelete this.xhr;\n\t\t}\n\n\t\t// take care of tab labels\n\t\tthis._cleanup();\n\t\treturn this;\n\t},\n\n\turl: function( index, url ) {\n\t\tthis.anchors.eq( index ).removeData( \"cache.tabs\" ).data( \"load.tabs\", url );\n\t\treturn this;\n\t},\n\n\tlength: function() {\n\t\treturn this.anchors.length;\n\t}\n});\n\n$.extend( $.ui.tabs, {\n\tversion: \"1.8.6\"\n});\n\n/*\n * Tabs Extensions\n */\n\n/*\n * Rotate\n */\n$.extend( $.ui.tabs.prototype, {\n\trotation: null,\n\trotate: function( ms, continuing ) {\n\t\tvar self = this,\n\t\t\to = this.options;\n\n\t\tvar rotate = self._rotate || ( self._rotate = function( e ) {\n\t\t\tclearTimeout( self.rotation );\n\t\t\tself.rotation = setTimeout(function() {\n\t\t\t\tvar t = o.selected;\n\t\t\t\tself.select( ++t < self.anchors.length ? t : 0 );\n\t\t\t}, ms );\n\t\t\t\n\t\t\tif ( e ) {\n\t\t\t\te.stopPropagation();\n\t\t\t}\n\t\t});\n\n\t\tvar stop = self._unrotate || ( self._unrotate = !continuing\n\t\t\t? function(e) {\n\t\t\t\tif (e.clientX) { // in case of a true click\n\t\t\t\t\tself.rotate(null);\n\t\t\t\t}\n\t\t\t}\n\t\t\t: function( e ) {\n\t\t\t\tt = o.selected;\n\t\t\t\trotate();\n\t\t\t});\n\n\t\t// start rotation\n\t\tif ( ms ) {\n\t\t\tthis.element.bind( \"tabsshow\", rotate );\n\t\t\tthis.anchors.bind( o.event + \".tabs\", stop );\n\t\t\trotate();\n\t\t// stop rotation\n\t\t} else {\n\t\t\tclearTimeout( self.rotation );\n\t\t\tthis.element.unbind( \"tabsshow\", rotate );\n\t\t\tthis.anchors.unbind( o.event + \".tabs\", stop );\n\t\t\tdelete this._rotate;\n\t\t\tdelete this._unrotate;\n\t\t}\n\n\t\treturn this;\n\t}\n});\n\n})( jQuery );\n/*\n * jQuery UI Datepicker 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Datepicker\n *\n * Depends:\n *\tjquery.ui.core.js\n */\n(function( $, undefined ) {\n\n$.extend($.ui, { datepicker: { version: \"1.8.6\" } });\n\nvar PROP_NAME = 'datepicker';\nvar dpuuid = new Date().getTime();\n\n/* Date picker manager.\n   Use the singleton instance of this class, $.datepicker, to interact with the date picker.\n   Settings for (groups of) date pickers are maintained in an instance object,\n   allowing multiple different settings on the same page. */\n\nfunction Datepicker() {\n\tthis.debug = false; // Change this to true to start debugging\n\tthis._curInst = null; // The current instance in use\n\tthis._keyEvent = false; // If the last event was a key event\n\tthis._disabledInputs = []; // List of date picker inputs that have been disabled\n\tthis._datepickerShowing = false; // True if the popup picker is showing , false if not\n\tthis._inDialog = false; // True if showing within a \"dialog\", false if not\n\tthis._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division\n\tthis._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class\n\tthis._appendClass = 'ui-datepicker-append'; // The name of the append marker class\n\tthis._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class\n\tthis._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class\n\tthis._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class\n\tthis._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class\n\tthis._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class\n\tthis._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class\n\tthis.regional = []; // Available regional settings, indexed by language code\n\tthis.regional[''] = { // Default regional settings\n\t\tcloseText: 'Done', // Display text for close link\n\t\tprevText: 'Prev', // Display text for previous month link\n\t\tnextText: 'Next', // Display text for next month link\n\t\tcurrentText: 'Today', // Display text for current month link\n\t\tmonthNames: ['January','February','March','April','May','June',\n\t\t\t'July','August','September','October','November','December'], // Names of months for drop-down and formatting\n\t\tmonthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting\n\t\tdayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting\n\t\tdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting\n\t\tdayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday\n\t\tweekHeader: 'Wk', // Column header for week of the year\n\t\tdateFormat: 'mm/dd/yy', // See format options on parseDate\n\t\tfirstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...\n\t\tisRTL: false, // True if right-to-left language, false if left-to-right\n\t\tshowMonthAfterYear: false, // True if the year select precedes month, false for month then year\n\t\tyearSuffix: '' // Additional text to append to the year in the month headers\n\t};\n\tthis._defaults = { // Global defaults for all the date picker instances\n\t\tshowOn: 'focus', // 'focus' for popup on focus,\n\t\t\t// 'button' for trigger button, or 'both' for either\n\t\tshowAnim: 'fadeIn', // Name of jQuery animation for popup\n\t\tshowOptions: {}, // Options for enhanced animations\n\t\tdefaultDate: null, // Used when field is blank: actual date,\n\t\t\t// +/-number for offset from today, null for today\n\t\tappendText: '', // Display text following the input box, e.g. showing the format\n\t\tbuttonText: '...', // Text for trigger button\n\t\tbuttonImage: '', // URL for trigger button image\n\t\tbuttonImageOnly: false, // True if the image appears alone, false if it appears on a button\n\t\thideIfNoPrevNext: false, // True to hide next/previous month links\n\t\t\t// if not applicable, false to just disable them\n\t\tnavigationAsDateFormat: false, // True if date formatting applied to prev/today/next links\n\t\tgotoCurrent: false, // True if today link goes back to current selection instead\n\t\tchangeMonth: false, // True if month can be selected directly, false if only prev/next\n\t\tchangeYear: false, // True if year can be selected directly, false if only prev/next\n\t\tyearRange: 'c-10:c+10', // Range of years to display in drop-down,\n\t\t\t// either relative to today's year (-nn:+nn), relative to currently displayed year\n\t\t\t// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)\n\t\tshowOtherMonths: false, // True to show dates in other months, false to leave blank\n\t\tselectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable\n\t\tshowWeek: false, // True to show week of the year, false to not show it\n\t\tcalculateWeek: this.iso8601Week, // How to calculate the week of the year,\n\t\t\t// takes a Date and returns the number of the week for it\n\t\tshortYearCutoff: '+10', // Short year values < this are in the current century,\n\t\t\t// > this are in the previous century,\n\t\t\t// string value starting with '+' for current year + value\n\t\tminDate: null, // The earliest selectable date, or null for no limit\n\t\tmaxDate: null, // The latest selectable date, or null for no limit\n\t\tduration: 'fast', // Duration of display/closure\n\t\tbeforeShowDay: null, // Function that takes a date and returns an array with\n\t\t\t// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',\n\t\t\t// [2] = cell title (optional), e.g. $.datepicker.noWeekends\n\t\tbeforeShow: null, // Function that takes an input field and\n\t\t\t// returns a set of custom settings for the date picker\n\t\tonSelect: null, // Define a callback function when a date is selected\n\t\tonChangeMonthYear: null, // Define a callback function when the month or year is changed\n\t\tonClose: null, // Define a callback function when the datepicker is closed\n\t\tnumberOfMonths: 1, // Number of months to show at a time\n\t\tshowCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)\n\t\tstepMonths: 1, // Number of months to step back/forward\n\t\tstepBigMonths: 12, // Number of months to step back/forward for the big links\n\t\taltField: '', // Selector for an alternate field to store selected dates into\n\t\taltFormat: '', // The date format to use for the alternate field\n\t\tconstrainInput: true, // The input is constrained by the current date format\n\t\tshowButtonPanel: false, // True to show button panel, false to not show it\n\t\tautoSize: false // True to size the input for the date format, false to leave as is\n\t};\n\t$.extend(this._defaults, this.regional['']);\n\tthis.dpDiv = $('<div id=\"' + this._mainDivId + '\" class=\"ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible\"></div>');\n}\n\n$.extend(Datepicker.prototype, {\n\t/* Class name added to elements to indicate already configured with a date picker. */\n\tmarkerClassName: 'hasDatepicker',\n\n\t/* Debug logging (if enabled). */\n\tlog: function () {\n\t\tif (this.debug)\n\t\t\tconsole.log.apply('', arguments);\n\t},\n\t\n\t// TODO rename to \"widget\" when switching to widget factory\n\t_widgetDatepicker: function() {\n\t\treturn this.dpDiv;\n\t},\n\n\t/* Override the default settings for all instances of the date picker.\n\t   @param  settings  object - the new settings to use as defaults (anonymous object)\n\t   @return the manager object */\n\tsetDefaults: function(settings) {\n\t\textendRemove(this._defaults, settings || {});\n\t\treturn this;\n\t},\n\n\t/* Attach the date picker to a jQuery selection.\n\t   @param  target    element - the target input field or division or span\n\t   @param  settings  object - the new settings to use for this date picker instance (anonymous) */\n\t_attachDatepicker: function(target, settings) {\n\t\t// check for settings on the control itself - in namespace 'date:'\n\t\tvar inlineSettings = null;\n\t\tfor (var attrName in this._defaults) {\n\t\t\tvar attrValue = target.getAttribute('date:' + attrName);\n\t\t\tif (attrValue) {\n\t\t\t\tinlineSettings = inlineSettings || {};\n\t\t\t\ttry {\n\t\t\t\t\tinlineSettings[attrName] = eval(attrValue);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tinlineSettings[attrName] = attrValue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvar nodeName = target.nodeName.toLowerCase();\n\t\tvar inline = (nodeName == 'div' || nodeName == 'span');\n\t\tif (!target.id) {\n\t\t\tthis.uuid += 1;\n\t\t\ttarget.id = 'dp' + this.uuid;\n\t\t}\n\t\tvar inst = this._newInst($(target), inline);\n\t\tinst.settings = $.extend({}, settings || {}, inlineSettings || {});\n\t\tif (nodeName == 'input') {\n\t\t\tthis._connectDatepicker(target, inst);\n\t\t} else if (inline) {\n\t\t\tthis._inlineDatepicker(target, inst);\n\t\t}\n\t},\n\n\t/* Create a new instance object. */\n\t_newInst: function(target, inline) {\n\t\tvar id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\\\\\$1'); // escape jQuery meta chars\n\t\treturn {id: id, input: target, // associated target\n\t\t\tselectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection\n\t\t\tdrawMonth: 0, drawYear: 0, // month being drawn\n\t\t\tinline: inline, // is datepicker inline or not\n\t\t\tdpDiv: (!inline ? this.dpDiv : // presentation div\n\t\t\t$('<div class=\"' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all\"></div>'))};\n\t},\n\n\t/* Attach the date picker to an input field. */\n\t_connectDatepicker: function(target, inst) {\n\t\tvar input = $(target);\n\t\tinst.append = $([]);\n\t\tinst.trigger = $([]);\n\t\tif (input.hasClass(this.markerClassName))\n\t\t\treturn;\n\t\tthis._attachments(input, inst);\n\t\tinput.addClass(this.markerClassName).keydown(this._doKeyDown).\n\t\t\tkeypress(this._doKeyPress).keyup(this._doKeyUp).\n\t\t\tbind(\"setData.datepicker\", function(event, key, value) {\n\t\t\t\tinst.settings[key] = value;\n\t\t\t}).bind(\"getData.datepicker\", function(event, key) {\n\t\t\t\treturn this._get(inst, key);\n\t\t\t});\n\t\tthis._autoSize(inst);\n\t\t$.data(target, PROP_NAME, inst);\n\t},\n\n\t/* Make attachments based on settings. */\n\t_attachments: function(input, inst) {\n\t\tvar appendText = this._get(inst, 'appendText');\n\t\tvar isRTL = this._get(inst, 'isRTL');\n\t\tif (inst.append)\n\t\t\tinst.append.remove();\n\t\tif (appendText) {\n\t\t\tinst.append = $('<span class=\"' + this._appendClass + '\">' + appendText + '</span>');\n\t\t\tinput[isRTL ? 'before' : 'after'](inst.append);\n\t\t}\n\t\tinput.unbind('focus', this._showDatepicker);\n\t\tif (inst.trigger)\n\t\t\tinst.trigger.remove();\n\t\tvar showOn = this._get(inst, 'showOn');\n\t\tif (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field\n\t\t\tinput.focus(this._showDatepicker);\n\t\tif (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked\n\t\t\tvar buttonText = this._get(inst, 'buttonText');\n\t\t\tvar buttonImage = this._get(inst, 'buttonImage');\n\t\t\tinst.trigger = $(this._get(inst, 'buttonImageOnly') ?\n\t\t\t\t$('<img/>').addClass(this._triggerClass).\n\t\t\t\t\tattr({ src: buttonImage, alt: buttonText, title: buttonText }) :\n\t\t\t\t$('<button type=\"button\"></button>').addClass(this._triggerClass).\n\t\t\t\t\thtml(buttonImage == '' ? buttonText : $('<img/>').attr(\n\t\t\t\t\t{ src:buttonImage, alt:buttonText, title:buttonText })));\n\t\t\tinput[isRTL ? 'before' : 'after'](inst.trigger);\n\t\t\tinst.trigger.click(function() {\n\t\t\t\tif ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0])\n\t\t\t\t\t$.datepicker._hideDatepicker();\n\t\t\t\telse\n\t\t\t\t\t$.datepicker._showDatepicker(input[0]);\n\t\t\t\treturn false;\n\t\t\t});\n\t\t}\n\t},\n\n\t/* Apply the maximum length for the date format. */\n\t_autoSize: function(inst) {\n\t\tif (this._get(inst, 'autoSize') && !inst.inline) {\n\t\t\tvar date = new Date(2009, 12 - 1, 20); // Ensure double digits\n\t\t\tvar dateFormat = this._get(inst, 'dateFormat');\n\t\t\tif (dateFormat.match(/[DM]/)) {\n\t\t\t\tvar findMax = function(names) {\n\t\t\t\t\tvar max = 0;\n\t\t\t\t\tvar maxI = 0;\n\t\t\t\t\tfor (var i = 0; i < names.length; i++) {\n\t\t\t\t\t\tif (names[i].length > max) {\n\t\t\t\t\t\t\tmax = names[i].length;\n\t\t\t\t\t\t\tmaxI = i;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn maxI;\n\t\t\t\t};\n\t\t\t\tdate.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?\n\t\t\t\t\t'monthNames' : 'monthNamesShort'))));\n\t\t\t\tdate.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?\n\t\t\t\t\t'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());\n\t\t\t}\n\t\t\tinst.input.attr('size', this._formatDate(inst, date).length);\n\t\t}\n\t},\n\n\t/* Attach an inline date picker to a div. */\n\t_inlineDatepicker: function(target, inst) {\n\t\tvar divSpan = $(target);\n\t\tif (divSpan.hasClass(this.markerClassName))\n\t\t\treturn;\n\t\tdivSpan.addClass(this.markerClassName).append(inst.dpDiv).\n\t\t\tbind(\"setData.datepicker\", function(event, key, value){\n\t\t\t\tinst.settings[key] = value;\n\t\t\t}).bind(\"getData.datepicker\", function(event, key){\n\t\t\t\treturn this._get(inst, key);\n\t\t\t});\n\t\t$.data(target, PROP_NAME, inst);\n\t\tthis._setDate(inst, this._getDefaultDate(inst), true);\n\t\tthis._updateDatepicker(inst);\n\t\tthis._updateAlternate(inst);\n\t},\n\n\t/* Pop-up the date picker in a \"dialog\" box.\n\t   @param  input     element - ignored\n\t   @param  date      string or Date - the initial date to display\n\t   @param  onSelect  function - the function to call when a date is selected\n\t   @param  settings  object - update the dialog date picker instance's settings (anonymous object)\n\t   @param  pos       int[2] - coordinates for the dialog's position within the screen or\n\t                     event - with x/y coordinates or\n\t                     leave empty for default (screen centre)\n\t   @return the manager object */\n\t_dialogDatepicker: function(input, date, onSelect, settings, pos) {\n\t\tvar inst = this._dialogInst; // internal instance\n\t\tif (!inst) {\n\t\t\tthis.uuid += 1;\n\t\t\tvar id = 'dp' + this.uuid;\n\t\t\tthis._dialogInput = $('<input type=\"text\" id=\"' + id +\n\t\t\t\t'\" style=\"position: absolute; top: -100px; width: 0px; z-index: -10;\"/>');\n\t\t\tthis._dialogInput.keydown(this._doKeyDown);\n\t\t\t$('body').append(this._dialogInput);\n\t\t\tinst = this._dialogInst = this._newInst(this._dialogInput, false);\n\t\t\tinst.settings = {};\n\t\t\t$.data(this._dialogInput[0], PROP_NAME, inst);\n\t\t}\n\t\textendRemove(inst.settings, settings || {});\n\t\tdate = (date && date.constructor == Date ? this._formatDate(inst, date) : date);\n\t\tthis._dialogInput.val(date);\n\n\t\tthis._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);\n\t\tif (!this._pos) {\n\t\t\tvar browserWidth = document.documentElement.clientWidth;\n\t\t\tvar browserHeight = document.documentElement.clientHeight;\n\t\t\tvar scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;\n\t\t\tvar scrollY = document.documentElement.scrollTop || document.body.scrollTop;\n\t\t\tthis._pos = // should use actual width/height below\n\t\t\t\t[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];\n\t\t}\n\n\t\t// move input on screen for focus, but hidden behind dialog\n\t\tthis._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');\n\t\tinst.settings.onSelect = onSelect;\n\t\tthis._inDialog = true;\n\t\tthis.dpDiv.addClass(this._dialogClass);\n\t\tthis._showDatepicker(this._dialogInput[0]);\n\t\tif ($.blockUI)\n\t\t\t$.blockUI(this.dpDiv);\n\t\t$.data(this._dialogInput[0], PROP_NAME, inst);\n\t\treturn this;\n\t},\n\n\t/* Detach a datepicker from its control.\n\t   @param  target    element - the target input field or division or span */\n\t_destroyDatepicker: function(target) {\n\t\tvar $target = $(target);\n\t\tvar inst = $.data(target, PROP_NAME);\n\t\tif (!$target.hasClass(this.markerClassName)) {\n\t\t\treturn;\n\t\t}\n\t\tvar nodeName = target.nodeName.toLowerCase();\n\t\t$.removeData(target, PROP_NAME);\n\t\tif (nodeName == 'input') {\n\t\t\tinst.append.remove();\n\t\t\tinst.trigger.remove();\n\t\t\t$target.removeClass(this.markerClassName).\n\t\t\t\tunbind('focus', this._showDatepicker).\n\t\t\t\tunbind('keydown', this._doKeyDown).\n\t\t\t\tunbind('keypress', this._doKeyPress).\n\t\t\t\tunbind('keyup', this._doKeyUp);\n\t\t} else if (nodeName == 'div' || nodeName == 'span')\n\t\t\t$target.removeClass(this.markerClassName).empty();\n\t},\n\n\t/* Enable the date picker to a jQuery selection.\n\t   @param  target    element - the target input field or division or span */\n\t_enableDatepicker: function(target) {\n\t\tvar $target = $(target);\n\t\tvar inst = $.data(target, PROP_NAME);\n\t\tif (!$target.hasClass(this.markerClassName)) {\n\t\t\treturn;\n\t\t}\n\t\tvar nodeName = target.nodeName.toLowerCase();\n\t\tif (nodeName == 'input') {\n\t\t\ttarget.disabled = false;\n\t\t\tinst.trigger.filter('button').\n\t\t\t\teach(function() { this.disabled = false; }).end().\n\t\t\t\tfilter('img').css({opacity: '1.0', cursor: ''});\n\t\t}\n\t\telse if (nodeName == 'div' || nodeName == 'span') {\n\t\t\tvar inline = $target.children('.' + this._inlineClass);\n\t\t\tinline.children().removeClass('ui-state-disabled');\n\t\t}\n\t\tthis._disabledInputs = $.map(this._disabledInputs,\n\t\t\tfunction(value) { return (value == target ? null : value); }); // delete entry\n\t},\n\n\t/* Disable the date picker to a jQuery selection.\n\t   @param  target    element - the target input field or division or span */\n\t_disableDatepicker: function(target) {\n\t\tvar $target = $(target);\n\t\tvar inst = $.data(target, PROP_NAME);\n\t\tif (!$target.hasClass(this.markerClassName)) {\n\t\t\treturn;\n\t\t}\n\t\tvar nodeName = target.nodeName.toLowerCase();\n\t\tif (nodeName == 'input') {\n\t\t\ttarget.disabled = true;\n\t\t\tinst.trigger.filter('button').\n\t\t\t\teach(function() { this.disabled = true; }).end().\n\t\t\t\tfilter('img').css({opacity: '0.5', cursor: 'default'});\n\t\t}\n\t\telse if (nodeName == 'div' || nodeName == 'span') {\n\t\t\tvar inline = $target.children('.' + this._inlineClass);\n\t\t\tinline.children().addClass('ui-state-disabled');\n\t\t}\n\t\tthis._disabledInputs = $.map(this._disabledInputs,\n\t\t\tfunction(value) { return (value == target ? null : value); }); // delete entry\n\t\tthis._disabledInputs[this._disabledInputs.length] = target;\n\t},\n\n\t/* Is the first field in a jQuery collection disabled as a datepicker?\n\t   @param  target    element - the target input field or division or span\n\t   @return boolean - true if disabled, false if enabled */\n\t_isDisabledDatepicker: function(target) {\n\t\tif (!target) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (var i = 0; i < this._disabledInputs.length; i++) {\n\t\t\tif (this._disabledInputs[i] == target)\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t},\n\n\t/* Retrieve the instance data for the target control.\n\t   @param  target  element - the target input field or division or span\n\t   @return  object - the associated instance data\n\t   @throws  error if a jQuery problem getting data */\n\t_getInst: function(target) {\n\t\ttry {\n\t\t\treturn $.data(target, PROP_NAME);\n\t\t}\n\t\tcatch (err) {\n\t\t\tthrow 'Missing instance data for this datepicker';\n\t\t}\n\t},\n\n\t/* Update or retrieve the settings for a date picker attached to an input field or division.\n\t   @param  target  element - the target input field or division or span\n\t   @param  name    object - the new settings to update or\n\t                   string - the name of the setting to change or retrieve,\n\t                   when retrieving also 'all' for all instance settings or\n\t                   'defaults' for all global defaults\n\t   @param  value   any - the new value for the setting\n\t                   (omit if above is an object or to retrieve a value) */\n\t_optionDatepicker: function(target, name, value) {\n\t\tvar inst = this._getInst(target);\n\t\tif (arguments.length == 2 && typeof name == 'string') {\n\t\t\treturn (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :\n\t\t\t\t(inst ? (name == 'all' ? $.extend({}, inst.settings) :\n\t\t\t\tthis._get(inst, name)) : null));\n\t\t}\n\t\tvar settings = name || {};\n\t\tif (typeof name == 'string') {\n\t\t\tsettings = {};\n\t\t\tsettings[name] = value;\n\t\t}\n\t\tif (inst) {\n\t\t\tif (this._curInst == inst) {\n\t\t\t\tthis._hideDatepicker();\n\t\t\t}\n\t\t\tvar date = this._getDateDatepicker(target, true);\n\t\t\textendRemove(inst.settings, settings);\n\t\t\tthis._attachments($(target), inst);\n\t\t\tthis._autoSize(inst);\n\t\t\tthis._setDateDatepicker(target, date);\n\t\t\tthis._updateDatepicker(inst);\n\t\t}\n\t},\n\n\t// change method deprecated\n\t_changeDatepicker: function(target, name, value) {\n\t\tthis._optionDatepicker(target, name, value);\n\t},\n\n\t/* Redraw the date picker attached to an input field or division.\n\t   @param  target  element - the target input field or division or span */\n\t_refreshDatepicker: function(target) {\n\t\tvar inst = this._getInst(target);\n\t\tif (inst) {\n\t\t\tthis._updateDatepicker(inst);\n\t\t}\n\t},\n\n\t/* Set the dates for a jQuery selection.\n\t   @param  target   element - the target input field or division or span\n\t   @param  date     Date - the new date */\n\t_setDateDatepicker: function(target, date) {\n\t\tvar inst = this._getInst(target);\n\t\tif (inst) {\n\t\t\tthis._setDate(inst, date);\n\t\t\tthis._updateDatepicker(inst);\n\t\t\tthis._updateAlternate(inst);\n\t\t}\n\t},\n\n\t/* Get the date(s) for the first entry in a jQuery selection.\n\t   @param  target     element - the target input field or division or span\n\t   @param  noDefault  boolean - true if no default date is to be used\n\t   @return Date - the current date */\n\t_getDateDatepicker: function(target, noDefault) {\n\t\tvar inst = this._getInst(target);\n\t\tif (inst && !inst.inline)\n\t\t\tthis._setDateFromField(inst, noDefault);\n\t\treturn (inst ? this._getDate(inst) : null);\n\t},\n\n\t/* Handle keystrokes. */\n\t_doKeyDown: function(event) {\n\t\tvar inst = $.datepicker._getInst(event.target);\n\t\tvar handled = true;\n\t\tvar isRTL = inst.dpDiv.is('.ui-datepicker-rtl');\n\t\tinst._keyEvent = true;\n\t\tif ($.datepicker._datepickerShowing)\n\t\t\tswitch (event.keyCode) {\n\t\t\t\tcase 9: $.datepicker._hideDatepicker();\n\t\t\t\t\t\thandled = false;\n\t\t\t\t\t\tbreak; // hide on tab out\n\t\t\t\tcase 13: var sel = $('td.' + $.datepicker._dayOverClass, inst.dpDiv).\n\t\t\t\t\t\t\tadd($('td.' + $.datepicker._currentClass, inst.dpDiv));\n\t\t\t\t\t\tif (sel[0])\n\t\t\t\t\t\t\t$.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t$.datepicker._hideDatepicker();\n\t\t\t\t\t\treturn false; // don't submit the form\n\t\t\t\t\t\tbreak; // select the value on enter\n\t\t\t\tcase 27: $.datepicker._hideDatepicker();\n\t\t\t\t\t\tbreak; // hide on escape\n\t\t\t\tcase 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?\n\t\t\t\t\t\t\t-$.datepicker._get(inst, 'stepBigMonths') :\n\t\t\t\t\t\t\t-$.datepicker._get(inst, 'stepMonths')), 'M');\n\t\t\t\t\t\tbreak; // previous month/year on page up/+ ctrl\n\t\t\t\tcase 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?\n\t\t\t\t\t\t\t+$.datepicker._get(inst, 'stepBigMonths') :\n\t\t\t\t\t\t\t+$.datepicker._get(inst, 'stepMonths')), 'M');\n\t\t\t\t\t\tbreak; // next month/year on page down/+ ctrl\n\t\t\t\tcase 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\tbreak; // clear on ctrl or command +end\n\t\t\t\tcase 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\tbreak; // current on ctrl or command +home\n\t\t\t\tcase 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\t// -1 day on ctrl or command +left\n\t\t\t\t\t\tif (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?\n\t\t\t\t\t\t\t\t\t-$.datepicker._get(inst, 'stepBigMonths') :\n\t\t\t\t\t\t\t\t\t-$.datepicker._get(inst, 'stepMonths')), 'M');\n\t\t\t\t\t\t// next month/year on alt +left on Mac\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\tbreak; // -1 week on ctrl or command +up\n\t\t\t\tcase 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\t// +1 day on ctrl or command +right\n\t\t\t\t\t\tif (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?\n\t\t\t\t\t\t\t\t\t+$.datepicker._get(inst, 'stepBigMonths') :\n\t\t\t\t\t\t\t\t\t+$.datepicker._get(inst, 'stepMonths')), 'M');\n\t\t\t\t\t\t// next month/year on alt +right\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');\n\t\t\t\t\t\thandled = event.ctrlKey || event.metaKey;\n\t\t\t\t\t\tbreak; // +1 week on ctrl or command +down\n\t\t\t\tdefault: handled = false;\n\t\t\t}\n\t\telse if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home\n\t\t\t$.datepicker._showDatepicker(this);\n\t\telse {\n\t\t\thandled = false;\n\t\t}\n\t\tif (handled) {\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t}\n\t},\n\n\t/* Filter entered characters - based on date format. */\n\t_doKeyPress: function(event) {\n\t\tvar inst = $.datepicker._getInst(event.target);\n\t\tif ($.datepicker._get(inst, 'constrainInput')) {\n\t\t\tvar chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));\n\t\t\tvar chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);\n\t\t\treturn event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);\n\t\t}\n\t},\n\n\t/* Synchronise manual entry and field/alternate field. */\n\t_doKeyUp: function(event) {\n\t\tvar inst = $.datepicker._getInst(event.target);\n\t\tif (inst.input.val() != inst.lastVal) {\n\t\t\ttry {\n\t\t\t\tvar date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),\n\t\t\t\t\t(inst.input ? inst.input.val() : null),\n\t\t\t\t\t$.datepicker._getFormatConfig(inst));\n\t\t\t\tif (date) { // only if valid\n\t\t\t\t\t$.datepicker._setDateFromField(inst);\n\t\t\t\t\t$.datepicker._updateAlternate(inst);\n\t\t\t\t\t$.datepicker._updateDatepicker(inst);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (event) {\n\t\t\t\t$.datepicker.log(event);\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t},\n\n\t/* Pop-up the date picker for a given input field.\n\t   @param  input  element - the input field attached to the date picker or\n\t                  event - if triggered by focus */\n\t_showDatepicker: function(input) {\n\t\tinput = input.target || input;\n\t\tif (input.nodeName.toLowerCase() != 'input') // find from button/image trigger\n\t\t\tinput = $('input', input.parentNode)[0];\n\t\tif ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here\n\t\t\treturn;\n\t\tvar inst = $.datepicker._getInst(input);\n\t\tif ($.datepicker._curInst && $.datepicker._curInst != inst) {\n\t\t\t$.datepicker._curInst.dpDiv.stop(true, true);\n\t\t}\n\t\tvar beforeShow = $.datepicker._get(inst, 'beforeShow');\n\t\textendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));\n\t\tinst.lastVal = null;\n\t\t$.datepicker._lastInput = input;\n\t\t$.datepicker._setDateFromField(inst);\n\t\tif ($.datepicker._inDialog) // hide cursor\n\t\t\tinput.value = '';\n\t\tif (!$.datepicker._pos) { // position below input\n\t\t\t$.datepicker._pos = $.datepicker._findPos(input);\n\t\t\t$.datepicker._pos[1] += input.offsetHeight; // add the height\n\t\t}\n\t\tvar isFixed = false;\n\t\t$(input).parents().each(function() {\n\t\t\tisFixed |= $(this).css('position') == 'fixed';\n\t\t\treturn !isFixed;\n\t\t});\n\t\tif (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled\n\t\t\t$.datepicker._pos[0] -= document.documentElement.scrollLeft;\n\t\t\t$.datepicker._pos[1] -= document.documentElement.scrollTop;\n\t\t}\n\t\tvar offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};\n\t\t$.datepicker._pos = null;\n\t\t// determine sizing offscreen\n\t\tinst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});\n\t\t$.datepicker._updateDatepicker(inst);\n\t\t// fix width for dynamic number of date pickers\n\t\t// and adjust position before showing\n\t\toffset = $.datepicker._checkOffset(inst, offset, isFixed);\n\t\tinst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?\n\t\t\t'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',\n\t\t\tleft: offset.left + 'px', top: offset.top + 'px'});\n\t\tif (!inst.inline) {\n\t\t\tvar showAnim = $.datepicker._get(inst, 'showAnim');\n\t\t\tvar duration = $.datepicker._get(inst, 'duration');\n\t\t\tvar postProcess = function() {\n\t\t\t\t$.datepicker._datepickerShowing = true;\n\t\t\t\tvar borders = $.datepicker._getBorders(inst.dpDiv);\n\t\t\t\tinst.dpDiv.find('iframe.ui-datepicker-cover'). // IE6- only\n\t\t\t\t\tcss({left: -borders[0], top: -borders[1],\n\t\t\t\t\t\twidth: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});\n\t\t\t};\n\t\t\tinst.dpDiv.zIndex($(input).zIndex()+1);\n\t\t\tif ($.effects && $.effects[showAnim])\n\t\t\t\tinst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);\n\t\t\telse\n\t\t\t\tinst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);\n\t\t\tif (!showAnim || !duration)\n\t\t\t\tpostProcess();\n\t\t\tif (inst.input.is(':visible') && !inst.input.is(':disabled'))\n\t\t\t\tinst.input.focus();\n\t\t\t$.datepicker._curInst = inst;\n\t\t}\n\t},\n\n\t/* Generate the date picker content. */\n\t_updateDatepicker: function(inst) {\n\t\tvar self = this;\n\t\tvar borders = $.datepicker._getBorders(inst.dpDiv);\n\t\tinst.dpDiv.empty().append(this._generateHTML(inst))\n\t\t\t.find('iframe.ui-datepicker-cover') // IE6- only\n\t\t\t\t.css({left: -borders[0], top: -borders[1],\n\t\t\t\t\twidth: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})\n\t\t\t.end()\n\t\t\t.find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a')\n\t\t\t\t.bind('mouseout', function(){\n\t\t\t\t\t$(this).removeClass('ui-state-hover');\n\t\t\t\t\tif(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');\n\t\t\t\t\tif(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');\n\t\t\t\t})\n\t\t\t\t.bind('mouseover', function(){\n\t\t\t\t\tif (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) {\n\t\t\t\t\t\t$(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');\n\t\t\t\t\t\t$(this).addClass('ui-state-hover');\n\t\t\t\t\t\tif(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');\n\t\t\t\t\t\tif(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t.end()\n\t\t\t.find('.' + this._dayOverClass + ' a')\n\t\t\t\t.trigger('mouseover')\n\t\t\t.end();\n\t\tvar numMonths = this._getNumberOfMonths(inst);\n\t\tvar cols = numMonths[1];\n\t\tvar width = 17;\n\t\tif (cols > 1)\n\t\t\tinst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');\n\t\telse\n\t\t\tinst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');\n\t\tinst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +\n\t\t\t'Class']('ui-datepicker-multi');\n\t\tinst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +\n\t\t\t'Class']('ui-datepicker-rtl');\n\t\tif (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&\n\t\t\t\tinst.input.is(':visible') && !inst.input.is(':disabled'))\n\t\t\tinst.input.focus();\n\t},\n\n\t/* Retrieve the size of left and top borders for an element.\n\t   @param  elem  (jQuery object) the element of interest\n\t   @return  (number[2]) the left and top borders */\n\t_getBorders: function(elem) {\n\t\tvar convert = function(value) {\n\t\t\treturn {thin: 1, medium: 2, thick: 3}[value] || value;\n\t\t};\n\t\treturn [parseFloat(convert(elem.css('border-left-width'))),\n\t\t\tparseFloat(convert(elem.css('border-top-width')))];\n\t},\n\n\t/* Check positioning to remain on screen. */\n\t_checkOffset: function(inst, offset, isFixed) {\n\t\tvar dpWidth = inst.dpDiv.outerWidth();\n\t\tvar dpHeight = inst.dpDiv.outerHeight();\n\t\tvar inputWidth = inst.input ? inst.input.outerWidth() : 0;\n\t\tvar inputHeight = inst.input ? inst.input.outerHeight() : 0;\n\t\tvar viewWidth = document.documentElement.clientWidth + $(document).scrollLeft();\n\t\tvar viewHeight = document.documentElement.clientHeight + $(document).scrollTop();\n\n\t\toffset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);\n\t\toffset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;\n\t\toffset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;\n\n\t\t// now check if datepicker is showing outside window viewport - move to a better place if so.\n\t\toffset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?\n\t\t\tMath.abs(offset.left + dpWidth - viewWidth) : 0);\n\t\toffset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?\n\t\t\tMath.abs(dpHeight + inputHeight) : 0);\n\n\t\treturn offset;\n\t},\n\n\t/* Find an object's position on the screen. */\n\t_findPos: function(obj) {\n\t\tvar inst = this._getInst(obj);\n\t\tvar isRTL = this._get(inst, 'isRTL');\n        while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {\n            obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];\n        }\n        var position = $(obj).offset();\n\t    return [position.left, position.top];\n\t},\n\n\t/* Hide the date picker from view.\n\t   @param  input  element - the input field attached to the date picker */\n\t_hideDatepicker: function(input) {\n\t\tvar inst = this._curInst;\n\t\tif (!inst || (input && inst != $.data(input, PROP_NAME)))\n\t\t\treturn;\n\t\tif (this._datepickerShowing) {\n\t\t\tvar showAnim = this._get(inst, 'showAnim');\n\t\t\tvar duration = this._get(inst, 'duration');\n\t\t\tvar postProcess = function() {\n\t\t\t\t$.datepicker._tidyDialog(inst);\n\t\t\t\tthis._curInst = null;\n\t\t\t};\n\t\t\tif ($.effects && $.effects[showAnim])\n\t\t\t\tinst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);\n\t\t\telse\n\t\t\t\tinst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :\n\t\t\t\t\t(showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);\n\t\t\tif (!showAnim)\n\t\t\t\tpostProcess();\n\t\t\tvar onClose = this._get(inst, 'onClose');\n\t\t\tif (onClose)\n\t\t\t\tonClose.apply((inst.input ? inst.input[0] : null),\n\t\t\t\t\t[(inst.input ? inst.input.val() : ''), inst]);  // trigger custom callback\n\t\t\tthis._datepickerShowing = false;\n\t\t\tthis._lastInput = null;\n\t\t\tif (this._inDialog) {\n\t\t\t\tthis._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });\n\t\t\t\tif ($.blockUI) {\n\t\t\t\t\t$.unblockUI();\n\t\t\t\t\t$('body').append(this.dpDiv);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._inDialog = false;\n\t\t}\n\t},\n\n\t/* Tidy up after a dialog display. */\n\t_tidyDialog: function(inst) {\n\t\tinst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');\n\t},\n\n\t/* Close date picker if clicked elsewhere. */\n\t_checkExternalClick: function(event) {\n\t\tif (!$.datepicker._curInst)\n\t\t\treturn;\n\t\tvar $target = $(event.target);\n\t\tif ($target[0].id != $.datepicker._mainDivId &&\n\t\t\t\t$target.parents('#' + $.datepicker._mainDivId).length == 0 &&\n\t\t\t\t!$target.hasClass($.datepicker.markerClassName) &&\n\t\t\t\t!$target.hasClass($.datepicker._triggerClass) &&\n\t\t\t\t$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))\n\t\t\t$.datepicker._hideDatepicker();\n\t},\n\n\t/* Adjust one of the date sub-fields. */\n\t_adjustDate: function(id, offset, period) {\n\t\tvar target = $(id);\n\t\tvar inst = this._getInst(target[0]);\n\t\tif (this._isDisabledDatepicker(target[0])) {\n\t\t\treturn;\n\t\t}\n\t\tthis._adjustInstDate(inst, offset +\n\t\t\t(period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning\n\t\t\tperiod);\n\t\tthis._updateDatepicker(inst);\n\t},\n\n\t/* Action for current link. */\n\t_gotoToday: function(id) {\n\t\tvar target = $(id);\n\t\tvar inst = this._getInst(target[0]);\n\t\tif (this._get(inst, 'gotoCurrent') && inst.currentDay) {\n\t\t\tinst.selectedDay = inst.currentDay;\n\t\t\tinst.drawMonth = inst.selectedMonth = inst.currentMonth;\n\t\t\tinst.drawYear = inst.selectedYear = inst.currentYear;\n\t\t}\n\t\telse {\n\t\t\tvar date = new Date();\n\t\t\tinst.selectedDay = date.getDate();\n\t\t\tinst.drawMonth = inst.selectedMonth = date.getMonth();\n\t\t\tinst.drawYear = inst.selectedYear = date.getFullYear();\n\t\t}\n\t\tthis._notifyChange(inst);\n\t\tthis._adjustDate(target);\n\t},\n\n\t/* Action for selecting a new month/year. */\n\t_selectMonthYear: function(id, select, period) {\n\t\tvar target = $(id);\n\t\tvar inst = this._getInst(target[0]);\n\t\tinst._selectingMonthYear = false;\n\t\tinst['selected' + (period == 'M' ? 'Month' : 'Year')] =\n\t\tinst['draw' + (period == 'M' ? 'Month' : 'Year')] =\n\t\t\tparseInt(select.options[select.selectedIndex].value,10);\n\t\tthis._notifyChange(inst);\n\t\tthis._adjustDate(target);\n\t},\n\n\t/* Restore input focus after not changing month/year. */\n\t_clickMonthYear: function(id) {\n\t\tvar target = $(id);\n\t\tvar inst = this._getInst(target[0]);\n\t\tif (inst.input && inst._selectingMonthYear) {\n\t\t\tsetTimeout(function() {\n\t\t\t\tinst.input.focus();\n\t\t\t}, 0);\n\t\t}\n\t\tinst._selectingMonthYear = !inst._selectingMonthYear;\n\t},\n\n\t/* Action for selecting a day. */\n\t_selectDay: function(id, month, year, td) {\n\t\tvar target = $(id);\n\t\tif ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {\n\t\t\treturn;\n\t\t}\n\t\tvar inst = this._getInst(target[0]);\n\t\tinst.selectedDay = inst.currentDay = $('a', td).html();\n\t\tinst.selectedMonth = inst.currentMonth = month;\n\t\tinst.selectedYear = inst.currentYear = year;\n\t\tthis._selectDate(id, this._formatDate(inst,\n\t\t\tinst.currentDay, inst.currentMonth, inst.currentYear));\n\t},\n\n\t/* Erase the input field and hide the date picker. */\n\t_clearDate: function(id) {\n\t\tvar target = $(id);\n\t\tvar inst = this._getInst(target[0]);\n\t\tthis._selectDate(target, '');\n\t},\n\n\t/* Update the input field with the selected date. */\n\t_selectDate: function(id, dateStr) {\n\t\tvar target = $(id);\n\t\tvar inst = this._getInst(target[0]);\n\t\tdateStr = (dateStr != null ? dateStr : this._formatDate(inst));\n\t\tif (inst.input)\n\t\t\tinst.input.val(dateStr);\n\t\tthis._updateAlternate(inst);\n\t\tvar onSelect = this._get(inst, 'onSelect');\n\t\tif (onSelect)\n\t\t\tonSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);  // trigger custom callback\n\t\telse if (inst.input)\n\t\t\tinst.input.trigger('change'); // fire the change event\n\t\tif (inst.inline)\n\t\t\tthis._updateDatepicker(inst);\n\t\telse {\n\t\t\tthis._hideDatepicker();\n\t\t\tthis._lastInput = inst.input[0];\n\t\t\tif (typeof(inst.input[0]) != 'object')\n\t\t\t\tinst.input.focus(); // restore focus\n\t\t\tthis._lastInput = null;\n\t\t}\n\t},\n\n\t/* Update any alternate field to synchronise with the main field. */\n\t_updateAlternate: function(inst) {\n\t\tvar altField = this._get(inst, 'altField');\n\t\tif (altField) { // update alternate field too\n\t\t\tvar altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');\n\t\t\tvar date = this._getDate(inst);\n\t\t\tvar dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));\n\t\t\t$(altField).each(function() { $(this).val(dateStr); });\n\t\t}\n\t},\n\n\t/* Set as beforeShowDay function to prevent selection of weekends.\n\t   @param  date  Date - the date to customise\n\t   @return [boolean, string] - is this date selectable?, what is its CSS class? */\n\tnoWeekends: function(date) {\n\t\tvar day = date.getDay();\n\t\treturn [(day > 0 && day < 6), ''];\n\t},\n\n\t/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.\n\t   @param  date  Date - the date to get the week for\n\t   @return  number - the number of the week within the year that contains this date */\n\tiso8601Week: function(date) {\n\t\tvar checkDate = new Date(date.getTime());\n\t\t// Find Thursday of this week starting on Monday\n\t\tcheckDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));\n\t\tvar time = checkDate.getTime();\n\t\tcheckDate.setMonth(0); // Compare with Jan 1\n\t\tcheckDate.setDate(1);\n\t\treturn Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;\n\t},\n\n\t/* Parse a string value into a date object.\n\t   See formatDate below for the possible formats.\n\n\t   @param  format    string - the expected format of the date\n\t   @param  value     string - the date in the above format\n\t   @param  settings  Object - attributes include:\n\t                     shortYearCutoff  number - the cutoff year for determining the century (optional)\n\t                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)\n\t                     dayNames         string[7] - names of the days from Sunday (optional)\n\t                     monthNamesShort  string[12] - abbreviated names of the months (optional)\n\t                     monthNames       string[12] - names of the months (optional)\n\t   @return  Date - the extracted date value or null if value is blank */\n\tparseDate: function (format, value, settings) {\n\t\tif (format == null || value == null)\n\t\t\tthrow 'Invalid arguments';\n\t\tvalue = (typeof value == 'object' ? value.toString() : value + '');\n\t\tif (value == '')\n\t\t\treturn null;\n\t\tvar shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;\n\t\tvar dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;\n\t\tvar dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;\n\t\tvar monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;\n\t\tvar monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;\n\t\tvar year = -1;\n\t\tvar month = -1;\n\t\tvar day = -1;\n\t\tvar doy = -1;\n\t\tvar literal = false;\n\t\t// Check whether a format character is doubled\n\t\tvar lookAhead = function(match) {\n\t\t\tvar matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);\n\t\t\tif (matches)\n\t\t\t\tiFormat++;\n\t\t\treturn matches;\n\t\t};\n\t\t// Extract a number from the string value\n\t\tvar getNumber = function(match) {\n\t\t\tlookAhead(match);\n\t\t\tvar size = (match == '@' ? 14 : (match == '!' ? 20 :\n\t\t\t\t(match == 'y' ? 4 : (match == 'o' ? 3 : 2))));\n\t\t\tvar digits = new RegExp('^\\\\d{1,' + size + '}');\n\t\t\tvar num = value.substring(iValue).match(digits);\n\t\t\tif (!num)\n\t\t\t\tthrow 'Missing number at position ' + iValue;\n\t\t\tiValue += num[0].length;\n\t\t\treturn parseInt(num[0], 10);\n\t\t};\n\t\t// Extract a name from the string value and convert to an index\n\t\tvar getName = function(match, shortNames, longNames) {\n\t\t\tvar names = (lookAhead(match) ? longNames : shortNames);\n\t\t\tfor (var i = 0; i < names.length; i++) {\n\t\t\t\tif (value.substr(iValue, names[i].length).toLowerCase() == names[i].toLowerCase()) {\n\t\t\t\t\tiValue += names[i].length;\n\t\t\t\t\treturn i + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow 'Unknown name at position ' + iValue;\n\t\t};\n\t\t// Confirm that a literal character matches the string value\n\t\tvar checkLiteral = function() {\n\t\t\tif (value.charAt(iValue) != format.charAt(iFormat))\n\t\t\t\tthrow 'Unexpected literal at position ' + iValue;\n\t\t\tiValue++;\n\t\t};\n\t\tvar iValue = 0;\n\t\tfor (var iFormat = 0; iFormat < format.length; iFormat++) {\n\t\t\tif (literal)\n\t\t\t\tif (format.charAt(iFormat) == \"'\" && !lookAhead(\"'\"))\n\t\t\t\t\tliteral = false;\n\t\t\t\telse\n\t\t\t\t\tcheckLiteral();\n\t\t\telse\n\t\t\t\tswitch (format.charAt(iFormat)) {\n\t\t\t\t\tcase 'd':\n\t\t\t\t\t\tday = getNumber('d');\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'D':\n\t\t\t\t\t\tgetName('D', dayNamesShort, dayNames);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'o':\n\t\t\t\t\t\tdoy = getNumber('o');\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'm':\n\t\t\t\t\t\tmonth = getNumber('m');\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'M':\n\t\t\t\t\t\tmonth = getName('M', monthNamesShort, monthNames);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'y':\n\t\t\t\t\t\tyear = getNumber('y');\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '@':\n\t\t\t\t\t\tvar date = new Date(getNumber('@'));\n\t\t\t\t\t\tyear = date.getFullYear();\n\t\t\t\t\t\tmonth = date.getMonth() + 1;\n\t\t\t\t\t\tday = date.getDate();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '!':\n\t\t\t\t\t\tvar date = new Date((getNumber('!') - this._ticksTo1970) / 10000);\n\t\t\t\t\t\tyear = date.getFullYear();\n\t\t\t\t\t\tmonth = date.getMonth() + 1;\n\t\t\t\t\t\tday = date.getDate();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\tif (lookAhead(\"'\"))\n\t\t\t\t\t\t\tcheckLiteral();\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tliteral = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tcheckLiteral();\n\t\t\t\t}\n\t\t}\n\t\tif (year == -1)\n\t\t\tyear = new Date().getFullYear();\n\t\telse if (year < 100)\n\t\t\tyear += new Date().getFullYear() - new Date().getFullYear() % 100 +\n\t\t\t\t(year <= shortYearCutoff ? 0 : -100);\n\t\tif (doy > -1) {\n\t\t\tmonth = 1;\n\t\t\tday = doy;\n\t\t\tdo {\n\t\t\t\tvar dim = this._getDaysInMonth(year, month - 1);\n\t\t\t\tif (day <= dim)\n\t\t\t\t\tbreak;\n\t\t\t\tmonth++;\n\t\t\t\tday -= dim;\n\t\t\t} while (true);\n\t\t}\n\t\tvar date = this._daylightSavingAdjust(new Date(year, month - 1, day));\n\t\tif (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)\n\t\t\tthrow 'Invalid date'; // E.g. 31/02/*\n\t\treturn date;\n\t},\n\n\t/* Standard date formats. */\n\tATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)\n\tCOOKIE: 'D, dd M yy',\n\tISO_8601: 'yy-mm-dd',\n\tRFC_822: 'D, d M y',\n\tRFC_850: 'DD, dd-M-y',\n\tRFC_1036: 'D, d M y',\n\tRFC_1123: 'D, d M yy',\n\tRFC_2822: 'D, d M yy',\n\tRSS: 'D, d M y', // RFC 822\n\tTICKS: '!',\n\tTIMESTAMP: '@',\n\tW3C: 'yy-mm-dd', // ISO 8601\n\n\t_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +\n\t\tMath.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),\n\n\t/* Format a date object into a string value.\n\t   The format can be combinations of the following:\n\t   d  - day of month (no leading zero)\n\t   dd - day of month (two digit)\n\t   o  - day of year (no leading zeros)\n\t   oo - day of year (three digit)\n\t   D  - day name short\n\t   DD - day name long\n\t   m  - month of year (no leading zero)\n\t   mm - month of year (two digit)\n\t   M  - month name short\n\t   MM - month name long\n\t   y  - year (two digit)\n\t   yy - year (four digit)\n\t   @ - Unix timestamp (ms since 01/01/1970)\n\t   ! - Windows ticks (100ns since 01/01/0001)\n\t   '...' - literal text\n\t   '' - single quote\n\n\t   @param  format    string - the desired format of the date\n\t   @param  date      Date - the date value to format\n\t   @param  settings  Object - attributes include:\n\t                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)\n\t                     dayNames         string[7] - names of the days from Sunday (optional)\n\t                     monthNamesShort  string[12] - abbreviated names of the months (optional)\n\t                     monthNames       string[12] - names of the months (optional)\n\t   @return  string - the date in the above format */\n\tformatDate: function (format, date, settings) {\n\t\tif (!date)\n\t\t\treturn '';\n\t\tvar dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;\n\t\tvar dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;\n\t\tvar monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;\n\t\tvar monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;\n\t\t// Check whether a format character is doubled\n\t\tvar lookAhead = function(match) {\n\t\t\tvar matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);\n\t\t\tif (matches)\n\t\t\t\tiFormat++;\n\t\t\treturn matches;\n\t\t};\n\t\t// Format a number, with leading zero if necessary\n\t\tvar formatNumber = function(match, value, len) {\n\t\t\tvar num = '' + value;\n\t\t\tif (lookAhead(match))\n\t\t\t\twhile (num.length < len)\n\t\t\t\t\tnum = '0' + num;\n\t\t\treturn num;\n\t\t};\n\t\t// Format a name, short or long as requested\n\t\tvar formatName = function(match, value, shortNames, longNames) {\n\t\t\treturn (lookAhead(match) ? longNames[value] : shortNames[value]);\n\t\t};\n\t\tvar output = '';\n\t\tvar literal = false;\n\t\tif (date)\n\t\t\tfor (var iFormat = 0; iFormat < format.length; iFormat++) {\n\t\t\t\tif (literal)\n\t\t\t\t\tif (format.charAt(iFormat) == \"'\" && !lookAhead(\"'\"))\n\t\t\t\t\t\tliteral = false;\n\t\t\t\t\telse\n\t\t\t\t\t\toutput += format.charAt(iFormat);\n\t\t\t\telse\n\t\t\t\t\tswitch (format.charAt(iFormat)) {\n\t\t\t\t\t\tcase 'd':\n\t\t\t\t\t\t\toutput += formatNumber('d', date.getDate(), 2);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'D':\n\t\t\t\t\t\t\toutput += formatName('D', date.getDay(), dayNamesShort, dayNames);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'o':\n\t\t\t\t\t\t\toutput += formatNumber('o',\n\t\t\t\t\t\t\t\t(date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000, 3);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'm':\n\t\t\t\t\t\t\toutput += formatNumber('m', date.getMonth() + 1, 2);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'M':\n\t\t\t\t\t\t\toutput += formatName('M', date.getMonth(), monthNamesShort, monthNames);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'y':\n\t\t\t\t\t\t\toutput += (lookAhead('y') ? date.getFullYear() :\n\t\t\t\t\t\t\t\t(date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase '@':\n\t\t\t\t\t\t\toutput += date.getTime();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase '!':\n\t\t\t\t\t\t\toutput += date.getTime() * 10000 + this._ticksTo1970;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\t\tif (lookAhead(\"'\"))\n\t\t\t\t\t\t\t\toutput += \"'\";\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tliteral = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\toutput += format.charAt(iFormat);\n\t\t\t\t\t}\n\t\t\t}\n\t\treturn output;\n\t},\n\n\t/* Extract all possible characters from the date format. */\n\t_possibleChars: function (format) {\n\t\tvar chars = '';\n\t\tvar literal = false;\n\t\t// Check whether a format character is doubled\n\t\tvar lookAhead = function(match) {\n\t\t\tvar matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);\n\t\t\tif (matches)\n\t\t\t\tiFormat++;\n\t\t\treturn matches;\n\t\t};\n\t\tfor (var iFormat = 0; iFormat < format.length; iFormat++)\n\t\t\tif (literal)\n\t\t\t\tif (format.charAt(iFormat) == \"'\" && !lookAhead(\"'\"))\n\t\t\t\t\tliteral = false;\n\t\t\t\telse\n\t\t\t\t\tchars += format.charAt(iFormat);\n\t\t\telse\n\t\t\t\tswitch (format.charAt(iFormat)) {\n\t\t\t\t\tcase 'd': case 'm': case 'y': case '@':\n\t\t\t\t\t\tchars += '0123456789';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'D': case 'M':\n\t\t\t\t\t\treturn null; // Accept anything\n\t\t\t\t\tcase \"'\":\n\t\t\t\t\t\tif (lookAhead(\"'\"))\n\t\t\t\t\t\t\tchars += \"'\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tliteral = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tchars += format.charAt(iFormat);\n\t\t\t\t}\n\t\treturn chars;\n\t},\n\n\t/* Get a setting value, defaulting if necessary. */\n\t_get: function(inst, name) {\n\t\treturn inst.settings[name] !== undefined ?\n\t\t\tinst.settings[name] : this._defaults[name];\n\t},\n\n\t/* Parse existing date and initialise date picker. */\n\t_setDateFromField: function(inst, noDefault) {\n\t\tif (inst.input.val() == inst.lastVal) {\n\t\t\treturn;\n\t\t}\n\t\tvar dateFormat = this._get(inst, 'dateFormat');\n\t\tvar dates = inst.lastVal = inst.input ? inst.input.val() : null;\n\t\tvar date, defaultDate;\n\t\tdate = defaultDate = this._getDefaultDate(inst);\n\t\tvar settings = this._getFormatConfig(inst);\n\t\ttry {\n\t\t\tdate = this.parseDate(dateFormat, dates, settings) || defaultDate;\n\t\t} catch (event) {\n\t\t\tthis.log(event);\n\t\t\tdates = (noDefault ? '' : dates);\n\t\t}\n\t\tinst.selectedDay = date.getDate();\n\t\tinst.drawMonth = inst.selectedMonth = date.getMonth();\n\t\tinst.drawYear = inst.selectedYear = date.getFullYear();\n\t\tinst.currentDay = (dates ? date.getDate() : 0);\n\t\tinst.currentMonth = (dates ? date.getMonth() : 0);\n\t\tinst.currentYear = (dates ? date.getFullYear() : 0);\n\t\tthis._adjustInstDate(inst);\n\t},\n\n\t/* Retrieve the default date shown on opening. */\n\t_getDefaultDate: function(inst) {\n\t\treturn this._restrictMinMax(inst,\n\t\t\tthis._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));\n\t},\n\n\t/* A date may be specified as an exact value or a relative one. */\n\t_determineDate: function(inst, date, defaultDate) {\n\t\tvar offsetNumeric = function(offset) {\n\t\t\tvar date = new Date();\n\t\t\tdate.setDate(date.getDate() + offset);\n\t\t\treturn date;\n\t\t};\n\t\tvar offsetString = function(offset) {\n\t\t\ttry {\n\t\t\t\treturn $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),\n\t\t\t\t\toffset, $.datepicker._getFormatConfig(inst));\n\t\t\t}\n\t\t\tcatch (e) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t\tvar date = (offset.toLowerCase().match(/^c/) ?\n\t\t\t\t$.datepicker._getDate(inst) : null) || new Date();\n\t\t\tvar year = date.getFullYear();\n\t\t\tvar month = date.getMonth();\n\t\t\tvar day = date.getDate();\n\t\t\tvar pattern = /([+-]?[0-9]+)\\s*(d|D|w|W|m|M|y|Y)?/g;\n\t\t\tvar matches = pattern.exec(offset);\n\t\t\twhile (matches) {\n\t\t\t\tswitch (matches[2] || 'd') {\n\t\t\t\t\tcase 'd' : case 'D' :\n\t\t\t\t\t\tday += parseInt(matches[1],10); break;\n\t\t\t\t\tcase 'w' : case 'W' :\n\t\t\t\t\t\tday += parseInt(matches[1],10) * 7; break;\n\t\t\t\t\tcase 'm' : case 'M' :\n\t\t\t\t\t\tmonth += parseInt(matches[1],10);\n\t\t\t\t\t\tday = Math.min(day, $.datepicker._getDaysInMonth(year, month));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'y': case 'Y' :\n\t\t\t\t\t\tyear += parseInt(matches[1],10);\n\t\t\t\t\t\tday = Math.min(day, $.datepicker._getDaysInMonth(year, month));\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmatches = pattern.exec(offset);\n\t\t\t}\n\t\t\treturn new Date(year, month, day);\n\t\t};\n\t\tdate = (date == null ? defaultDate : (typeof date == 'string' ? offsetString(date) :\n\t\t\t(typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date)));\n\t\tdate = (date && date.toString() == 'Invalid Date' ? defaultDate : date);\n\t\tif (date) {\n\t\t\tdate.setHours(0);\n\t\t\tdate.setMinutes(0);\n\t\t\tdate.setSeconds(0);\n\t\t\tdate.setMilliseconds(0);\n\t\t}\n\t\treturn this._daylightSavingAdjust(date);\n\t},\n\n\t/* Handle switch to/from daylight saving.\n\t   Hours may be non-zero on daylight saving cut-over:\n\t   > 12 when midnight changeover, but then cannot generate\n\t   midnight datetime, so jump to 1AM, otherwise reset.\n\t   @param  date  (Date) the date to check\n\t   @return  (Date) the corrected date */\n\t_daylightSavingAdjust: function(date) {\n\t\tif (!date) return null;\n\t\tdate.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\n\t\treturn date;\n\t},\n\n\t/* Set the date(s) directly. */\n\t_setDate: function(inst, date, noChange) {\n\t\tvar clear = !(date);\n\t\tvar origMonth = inst.selectedMonth;\n\t\tvar origYear = inst.selectedYear;\n\t\tdate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));\n\t\tinst.selectedDay = inst.currentDay = date.getDate();\n\t\tinst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();\n\t\tinst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();\n\t\tif ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange)\n\t\t\tthis._notifyChange(inst);\n\t\tthis._adjustInstDate(inst);\n\t\tif (inst.input) {\n\t\t\tinst.input.val(clear ? '' : this._formatDate(inst));\n\t\t}\n\t},\n\n\t/* Retrieve the date(s) directly. */\n\t_getDate: function(inst) {\n\t\tvar startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :\n\t\t\tthis._daylightSavingAdjust(new Date(\n\t\t\tinst.currentYear, inst.currentMonth, inst.currentDay)));\n\t\t\treturn startDate;\n\t},\n\n\t/* Generate the HTML for the current state of the date picker. */\n\t_generateHTML: function(inst) {\n\t\tvar today = new Date();\n\t\ttoday = this._daylightSavingAdjust(\n\t\t\tnew Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time\n\t\tvar isRTL = this._get(inst, 'isRTL');\n\t\tvar showButtonPanel = this._get(inst, 'showButtonPanel');\n\t\tvar hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');\n\t\tvar navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');\n\t\tvar numMonths = this._getNumberOfMonths(inst);\n\t\tvar showCurrentAtPos = this._get(inst, 'showCurrentAtPos');\n\t\tvar stepMonths = this._get(inst, 'stepMonths');\n\t\tvar isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);\n\t\tvar currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :\n\t\t\tnew Date(inst.currentYear, inst.currentMonth, inst.currentDay)));\n\t\tvar minDate = this._getMinMaxDate(inst, 'min');\n\t\tvar maxDate = this._getMinMaxDate(inst, 'max');\n\t\tvar drawMonth = inst.drawMonth - showCurrentAtPos;\n\t\tvar drawYear = inst.drawYear;\n\t\tif (drawMonth < 0) {\n\t\t\tdrawMonth += 12;\n\t\t\tdrawYear--;\n\t\t}\n\t\tif (maxDate) {\n\t\t\tvar maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),\n\t\t\t\tmaxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));\n\t\t\tmaxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);\n\t\t\twhile (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {\n\t\t\t\tdrawMonth--;\n\t\t\t\tif (drawMonth < 0) {\n\t\t\t\t\tdrawMonth = 11;\n\t\t\t\t\tdrawYear--;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tinst.drawMonth = drawMonth;\n\t\tinst.drawYear = drawYear;\n\t\tvar prevText = this._get(inst, 'prevText');\n\t\tprevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,\n\t\t\tthis._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),\n\t\t\tthis._getFormatConfig(inst)));\n\t\tvar prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?\n\t\t\t'<a class=\"ui-datepicker-prev ui-corner-all\" onclick=\"DP_jQuery_' + dpuuid +\n\t\t\t'.datepicker._adjustDate(\\'#' + inst.id + '\\', -' + stepMonths + ', \\'M\\');\"' +\n\t\t\t' title=\"' + prevText + '\"><span class=\"ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '\">' + prevText + '</span></a>' :\n\t\t\t(hideIfNoPrevNext ? '' : '<a class=\"ui-datepicker-prev ui-corner-all ui-state-disabled\" title=\"'+ prevText +'\"><span class=\"ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '\">' + prevText + '</span></a>'));\n\t\tvar nextText = this._get(inst, 'nextText');\n\t\tnextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,\n\t\t\tthis._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),\n\t\t\tthis._getFormatConfig(inst)));\n\t\tvar next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?\n\t\t\t'<a class=\"ui-datepicker-next ui-corner-all\" onclick=\"DP_jQuery_' + dpuuid +\n\t\t\t'.datepicker._adjustDate(\\'#' + inst.id + '\\', +' + stepMonths + ', \\'M\\');\"' +\n\t\t\t' title=\"' + nextText + '\"><span class=\"ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '\">' + nextText + '</span></a>' :\n\t\t\t(hideIfNoPrevNext ? '' : '<a class=\"ui-datepicker-next ui-corner-all ui-state-disabled\" title=\"'+ nextText + '\"><span class=\"ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '\">' + nextText + '</span></a>'));\n\t\tvar currentText = this._get(inst, 'currentText');\n\t\tvar gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);\n\t\tcurrentText = (!navigationAsDateFormat ? currentText :\n\t\t\tthis.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));\n\t\tvar controls = (!inst.inline ? '<button type=\"button\" class=\"ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all\" onclick=\"DP_jQuery_' + dpuuid +\n\t\t\t'.datepicker._hideDatepicker();\">' + this._get(inst, 'closeText') + '</button>' : '');\n\t\tvar buttonPanel = (showButtonPanel) ? '<div class=\"ui-datepicker-buttonpane ui-widget-content\">' + (isRTL ? controls : '') +\n\t\t\t(this._isInRange(inst, gotoDate) ? '<button type=\"button\" class=\"ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all\" onclick=\"DP_jQuery_' + dpuuid +\n\t\t\t'.datepicker._gotoToday(\\'#' + inst.id + '\\');\"' +\n\t\t\t'>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';\n\t\tvar firstDay = parseInt(this._get(inst, 'firstDay'),10);\n\t\tfirstDay = (isNaN(firstDay) ? 0 : firstDay);\n\t\tvar showWeek = this._get(inst, 'showWeek');\n\t\tvar dayNames = this._get(inst, 'dayNames');\n\t\tvar dayNamesShort = this._get(inst, 'dayNamesShort');\n\t\tvar dayNamesMin = this._get(inst, 'dayNamesMin');\n\t\tvar monthNames = this._get(inst, 'monthNames');\n\t\tvar monthNamesShort = this._get(inst, 'monthNamesShort');\n\t\tvar beforeShowDay = this._get(inst, 'beforeShowDay');\n\t\tvar showOtherMonths = this._get(inst, 'showOtherMonths');\n\t\tvar selectOtherMonths = this._get(inst, 'selectOtherMonths');\n\t\tvar calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;\n\t\tvar defaultDate = this._getDefaultDate(inst);\n\t\tvar html = '';\n\t\tfor (var row = 0; row < numMonths[0]; row++) {\n\t\t\tvar group = '';\n\t\t\tfor (var col = 0; col < numMonths[1]; col++) {\n\t\t\t\tvar selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));\n\t\t\t\tvar cornerClass = ' ui-corner-all';\n\t\t\t\tvar calender = '';\n\t\t\t\tif (isMultiMonth) {\n\t\t\t\t\tcalender += '<div class=\"ui-datepicker-group';\n\t\t\t\t\tif (numMonths[1] > 1)\n\t\t\t\t\t\tswitch (col) {\n\t\t\t\t\t\t\tcase 0: calender += ' ui-datepicker-group-first';\n\t\t\t\t\t\t\t\tcornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;\n\t\t\t\t\t\t\tcase numMonths[1]-1: calender += ' ui-datepicker-group-last';\n\t\t\t\t\t\t\t\tcornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;\n\t\t\t\t\t\t\tdefault: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;\n\t\t\t\t\t\t}\n\t\t\t\t\tcalender += '\">';\n\t\t\t\t}\n\t\t\t\tcalender += '<div class=\"ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '\">' +\n\t\t\t\t\t(/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +\n\t\t\t\t\t(/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +\n\t\t\t\t\tthis._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,\n\t\t\t\t\trow > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers\n\t\t\t\t\t'</div><table class=\"ui-datepicker-calendar\"><thead>' +\n\t\t\t\t\t'<tr>';\n\t\t\t\tvar thead = (showWeek ? '<th class=\"ui-datepicker-week-col\">' + this._get(inst, 'weekHeader') + '</th>' : '');\n\t\t\t\tfor (var dow = 0; dow < 7; dow++) { // days of the week\n\t\t\t\t\tvar day = (dow + firstDay) % 7;\n\t\t\t\t\tthead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class=\"ui-datepicker-week-end\"' : '') + '>' +\n\t\t\t\t\t\t'<span title=\"' + dayNames[day] + '\">' + dayNamesMin[day] + '</span></th>';\n\t\t\t\t}\n\t\t\t\tcalender += thead + '</tr></thead><tbody>';\n\t\t\t\tvar daysInMonth = this._getDaysInMonth(drawYear, drawMonth);\n\t\t\t\tif (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)\n\t\t\t\t\tinst.selectedDay = Math.min(inst.selectedDay, daysInMonth);\n\t\t\t\tvar leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;\n\t\t\t\tvar numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate\n\t\t\t\tvar printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));\n\t\t\t\tfor (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows\n\t\t\t\t\tcalender += '<tr>';\n\t\t\t\t\tvar tbody = (!showWeek ? '' : '<td class=\"ui-datepicker-week-col\">' +\n\t\t\t\t\t\tthis._get(inst, 'calculateWeek')(printDate) + '</td>');\n\t\t\t\t\tfor (var dow = 0; dow < 7; dow++) { // create date picker days\n\t\t\t\t\t\tvar daySettings = (beforeShowDay ?\n\t\t\t\t\t\t\tbeforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);\n\t\t\t\t\t\tvar otherMonth = (printDate.getMonth() != drawMonth);\n\t\t\t\t\t\tvar unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||\n\t\t\t\t\t\t\t(minDate && printDate < minDate) || (maxDate && printDate > maxDate);\n\t\t\t\t\t\ttbody += '<td class=\"' +\n\t\t\t\t\t\t\t((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends\n\t\t\t\t\t\t\t(otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months\n\t\t\t\t\t\t\t((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key\n\t\t\t\t\t\t\t(defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?\n\t\t\t\t\t\t\t// or defaultDate is current printedDate and defaultDate is selectedDate\n\t\t\t\t\t\t\t' ' + this._dayOverClass : '') + // highlight selected day\n\t\t\t\t\t\t\t(unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') +  // highlight unselectable days\n\t\t\t\t\t\t\t(otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates\n\t\t\t\t\t\t\t(printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day\n\t\t\t\t\t\t\t(printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '\"' + // highlight today (if different)\n\t\t\t\t\t\t\t((!otherMonth || showOtherMonths) && daySettings[2] ? ' title=\"' + daySettings[2] + '\"' : '') + // cell title\n\t\t\t\t\t\t\t(unselectable ? '' : ' onclick=\"DP_jQuery_' + dpuuid + '.datepicker._selectDay(\\'#' +\n\t\t\t\t\t\t\tinst.id + '\\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);return false;\"') + '>' + // actions\n\t\t\t\t\t\t\t(otherMonth && !showOtherMonths ? '&#xa0;' : // display for other months\n\t\t\t\t\t\t\t(unselectable ? '<span class=\"ui-state-default\">' + printDate.getDate() + '</span>' : '<a class=\"ui-state-default' +\n\t\t\t\t\t\t\t(printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +\n\t\t\t\t\t\t\t(printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day\n\t\t\t\t\t\t\t(otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months\n\t\t\t\t\t\t\t'\" href=\"#\">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date\n\t\t\t\t\t\tprintDate.setDate(printDate.getDate() + 1);\n\t\t\t\t\t\tprintDate = this._daylightSavingAdjust(printDate);\n\t\t\t\t\t}\n\t\t\t\t\tcalender += tbody + '</tr>';\n\t\t\t\t}\n\t\t\t\tdrawMonth++;\n\t\t\t\tif (drawMonth > 11) {\n\t\t\t\t\tdrawMonth = 0;\n\t\t\t\t\tdrawYear++;\n\t\t\t\t}\n\t\t\t\tcalender += '</tbody></table>' + (isMultiMonth ? '</div>' + \n\t\t\t\t\t\t\t((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class=\"ui-datepicker-row-break\"></div>' : '') : '');\n\t\t\t\tgroup += calender;\n\t\t\t}\n\t\t\thtml += group;\n\t\t}\n\t\thtml += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?\n\t\t\t'<iframe src=\"javascript:false;\" class=\"ui-datepicker-cover\" frameborder=\"0\"></iframe>' : '');\n\t\tinst._keyEvent = false;\n\t\treturn html;\n\t},\n\n\t/* Generate the month and year header. */\n\t_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,\n\t\t\tsecondary, monthNames, monthNamesShort) {\n\t\tvar changeMonth = this._get(inst, 'changeMonth');\n\t\tvar changeYear = this._get(inst, 'changeYear');\n\t\tvar showMonthAfterYear = this._get(inst, 'showMonthAfterYear');\n\t\tvar html = '<div class=\"ui-datepicker-title\">';\n\t\tvar monthHtml = '';\n\t\t// month selection\n\t\tif (secondary || !changeMonth)\n\t\t\tmonthHtml += '<span class=\"ui-datepicker-month\">' + monthNames[drawMonth] + '</span>';\n\t\telse {\n\t\t\tvar inMinYear = (minDate && minDate.getFullYear() == drawYear);\n\t\t\tvar inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);\n\t\t\tmonthHtml += '<select class=\"ui-datepicker-month\" ' +\n\t\t\t\t'onchange=\"DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\\'#' + inst.id + '\\', this, \\'M\\');\" ' +\n\t\t\t\t'onclick=\"DP_jQuery_' + dpuuid + '.datepicker._clickMonthYear(\\'#' + inst.id + '\\');\"' +\n\t\t\t \t'>';\n\t\t\tfor (var month = 0; month < 12; month++) {\n\t\t\t\tif ((!inMinYear || month >= minDate.getMonth()) &&\n\t\t\t\t\t\t(!inMaxYear || month <= maxDate.getMonth()))\n\t\t\t\t\tmonthHtml += '<option value=\"' + month + '\"' +\n\t\t\t\t\t\t(month == drawMonth ? ' selected=\"selected\"' : '') +\n\t\t\t\t\t\t'>' + monthNamesShort[month] + '</option>';\n\t\t\t}\n\t\t\tmonthHtml += '</select>';\n\t\t}\n\t\tif (!showMonthAfterYear)\n\t\t\thtml += monthHtml + (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '');\n\t\t// year selection\n\t\tif (secondary || !changeYear)\n\t\t\thtml += '<span class=\"ui-datepicker-year\">' + drawYear + '</span>';\n\t\telse {\n\t\t\t// determine range of years to display\n\t\t\tvar years = this._get(inst, 'yearRange').split(':');\n\t\t\tvar thisYear = new Date().getFullYear();\n\t\t\tvar determineYear = function(value) {\n\t\t\t\tvar year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :\n\t\t\t\t\t(value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :\n\t\t\t\t\tparseInt(value, 10)));\n\t\t\t\treturn (isNaN(year) ? thisYear : year);\n\t\t\t};\n\t\t\tvar year = determineYear(years[0]);\n\t\t\tvar endYear = Math.max(year, determineYear(years[1] || ''));\n\t\t\tyear = (minDate ? Math.max(year, minDate.getFullYear()) : year);\n\t\t\tendYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);\n\t\t\thtml += '<select class=\"ui-datepicker-year\" ' +\n\t\t\t\t'onchange=\"DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\\'#' + inst.id + '\\', this, \\'Y\\');\" ' +\n\t\t\t\t'onclick=\"DP_jQuery_' + dpuuid + '.datepicker._clickMonthYear(\\'#' + inst.id + '\\');\"' +\n\t\t\t\t'>';\n\t\t\tfor (; year <= endYear; year++) {\n\t\t\t\thtml += '<option value=\"' + year + '\"' +\n\t\t\t\t\t(year == drawYear ? ' selected=\"selected\"' : '') +\n\t\t\t\t\t'>' + year + '</option>';\n\t\t\t}\n\t\t\thtml += '</select>';\n\t\t}\n\t\thtml += this._get(inst, 'yearSuffix');\n\t\tif (showMonthAfterYear)\n\t\t\thtml += (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '') + monthHtml;\n\t\thtml += '</div>'; // Close datepicker_header\n\t\treturn html;\n\t},\n\n\t/* Adjust one of the date sub-fields. */\n\t_adjustInstDate: function(inst, offset, period) {\n\t\tvar year = inst.drawYear + (period == 'Y' ? offset : 0);\n\t\tvar month = inst.drawMonth + (period == 'M' ? offset : 0);\n\t\tvar day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +\n\t\t\t(period == 'D' ? offset : 0);\n\t\tvar date = this._restrictMinMax(inst,\n\t\t\tthis._daylightSavingAdjust(new Date(year, month, day)));\n\t\tinst.selectedDay = date.getDate();\n\t\tinst.drawMonth = inst.selectedMonth = date.getMonth();\n\t\tinst.drawYear = inst.selectedYear = date.getFullYear();\n\t\tif (period == 'M' || period == 'Y')\n\t\t\tthis._notifyChange(inst);\n\t},\n\n\t/* Ensure a date is within any min/max bounds. */\n\t_restrictMinMax: function(inst, date) {\n\t\tvar minDate = this._getMinMaxDate(inst, 'min');\n\t\tvar maxDate = this._getMinMaxDate(inst, 'max');\n\t\tdate = (minDate && date < minDate ? minDate : date);\n\t\tdate = (maxDate && date > maxDate ? maxDate : date);\n\t\treturn date;\n\t},\n\n\t/* Notify change of month/year. */\n\t_notifyChange: function(inst) {\n\t\tvar onChange = this._get(inst, 'onChangeMonthYear');\n\t\tif (onChange)\n\t\t\tonChange.apply((inst.input ? inst.input[0] : null),\n\t\t\t\t[inst.selectedYear, inst.selectedMonth + 1, inst]);\n\t},\n\n\t/* Determine the number of months to show. */\n\t_getNumberOfMonths: function(inst) {\n\t\tvar numMonths = this._get(inst, 'numberOfMonths');\n\t\treturn (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));\n\t},\n\n\t/* Determine the current maximum date - ensure no time components are set. */\n\t_getMinMaxDate: function(inst, minMax) {\n\t\treturn this._determineDate(inst, this._get(inst, minMax + 'Date'), null);\n\t},\n\n\t/* Find the number of days in a given month. */\n\t_getDaysInMonth: function(year, month) {\n\t\treturn 32 - new Date(year, month, 32).getDate();\n\t},\n\n\t/* Find the day of the week of the first of a month. */\n\t_getFirstDayOfMonth: function(year, month) {\n\t\treturn new Date(year, month, 1).getDay();\n\t},\n\n\t/* Determines if we should allow a \"next/prev\" month display change. */\n\t_canAdjustMonth: function(inst, offset, curYear, curMonth) {\n\t\tvar numMonths = this._getNumberOfMonths(inst);\n\t\tvar date = this._daylightSavingAdjust(new Date(curYear,\n\t\t\tcurMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));\n\t\tif (offset < 0)\n\t\t\tdate.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));\n\t\treturn this._isInRange(inst, date);\n\t},\n\n\t/* Is the given date in the accepted range? */\n\t_isInRange: function(inst, date) {\n\t\tvar minDate = this._getMinMaxDate(inst, 'min');\n\t\tvar maxDate = this._getMinMaxDate(inst, 'max');\n\t\treturn ((!minDate || date.getTime() >= minDate.getTime()) &&\n\t\t\t(!maxDate || date.getTime() <= maxDate.getTime()));\n\t},\n\n\t/* Provide the configuration settings for formatting/parsing. */\n\t_getFormatConfig: function(inst) {\n\t\tvar shortYearCutoff = this._get(inst, 'shortYearCutoff');\n\t\tshortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :\n\t\t\tnew Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));\n\t\treturn {shortYearCutoff: shortYearCutoff,\n\t\t\tdayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),\n\t\t\tmonthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};\n\t},\n\n\t/* Format the given date for display. */\n\t_formatDate: function(inst, day, month, year) {\n\t\tif (!day) {\n\t\t\tinst.currentDay = inst.selectedDay;\n\t\t\tinst.currentMonth = inst.selectedMonth;\n\t\t\tinst.currentYear = inst.selectedYear;\n\t\t}\n\t\tvar date = (day ? (typeof day == 'object' ? day :\n\t\t\tthis._daylightSavingAdjust(new Date(year, month, day))) :\n\t\t\tthis._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));\n\t\treturn this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));\n\t}\n});\n\n/* jQuery extend now ignores nulls! */\nfunction extendRemove(target, props) {\n\t$.extend(target, props);\n\tfor (var name in props)\n\t\tif (props[name] == null || props[name] == undefined)\n\t\t\ttarget[name] = props[name];\n\treturn target;\n};\n\n/* Determine whether an object is an array. */\nfunction isArray(a) {\n\treturn (a && (($.browser.safari && typeof a == 'object' && a.length) ||\n\t\t(a.constructor && a.constructor.toString().match(/\\Array\\(\\)/))));\n};\n\n/* Invoke the datepicker functionality.\n   @param  options  string - a command, optionally followed by additional parameters or\n                    Object - settings for attaching new datepicker functionality\n   @return  jQuery object */\n$.fn.datepicker = function(options){\n\n\t/* Initialise the date picker. */\n\tif (!$.datepicker.initialized) {\n\t\t$(document).mousedown($.datepicker._checkExternalClick).\n\t\t\tfind('body').append($.datepicker.dpDiv);\n\t\t$.datepicker.initialized = true;\n\t}\n\n\tvar otherArgs = Array.prototype.slice.call(arguments, 1);\n\tif (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget'))\n\t\treturn $.datepicker['_' + options + 'Datepicker'].\n\t\t\tapply($.datepicker, [this[0]].concat(otherArgs));\n\tif (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')\n\t\treturn $.datepicker['_' + options + 'Datepicker'].\n\t\t\tapply($.datepicker, [this[0]].concat(otherArgs));\n\treturn this.each(function() {\n\t\ttypeof options == 'string' ?\n\t\t\t$.datepicker['_' + options + 'Datepicker'].\n\t\t\t\tapply($.datepicker, [this].concat(otherArgs)) :\n\t\t\t$.datepicker._attachDatepicker(this, options);\n\t});\n};\n\n$.datepicker = new Datepicker(); // singleton instance\n$.datepicker.initialized = false;\n$.datepicker.uuid = new Date().getTime();\n$.datepicker.version = \"1.8.6\";\n\n// Workaround for #4055\n// Add another global to avoid noConflict issues with inline event handlers\nwindow['DP_jQuery_' + dpuuid] = $;\n\n})(jQuery);\n/*\n * jQuery UI Progressbar 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Progressbar\n *\n * Depends:\n *   jquery.ui.core.js\n *   jquery.ui.widget.js\n */\n(function( $, undefined ) {\n\n$.widget( \"ui.progressbar\", {\n\toptions: {\n\t\tvalue: 0\n\t},\n\n\tmin: 0,\n\tmax: 100,\n\n\t_create: function() {\n\t\tthis.element\n\t\t\t.addClass( \"ui-progressbar ui-widget ui-widget-content ui-corner-all\" )\n\t\t\t.attr({\n\t\t\t\trole: \"progressbar\",\n\t\t\t\t\"aria-valuemin\": this.min,\n\t\t\t\t\"aria-valuemax\": this.max,\n\t\t\t\t\"aria-valuenow\": this._value()\n\t\t\t});\n\n\t\tthis.valueDiv = $( \"<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>\" )\n\t\t\t.appendTo( this.element );\n\n\t\tthis._refreshValue();\n\t},\n\n\tdestroy: function() {\n\t\tthis.element\n\t\t\t.removeClass( \"ui-progressbar ui-widget ui-widget-content ui-corner-all\" )\n\t\t\t.removeAttr( \"role\" )\n\t\t\t.removeAttr( \"aria-valuemin\" )\n\t\t\t.removeAttr( \"aria-valuemax\" )\n\t\t\t.removeAttr( \"aria-valuenow\" );\n\n\t\tthis.valueDiv.remove();\n\n\t\t$.Widget.prototype.destroy.apply( this, arguments );\n\t},\n\n\tvalue: function( newValue ) {\n\t\tif ( newValue === undefined ) {\n\t\t\treturn this._value();\n\t\t}\n\n\t\tthis._setOption( \"value\", newValue );\n\t\treturn this;\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key === \"value\" ) {\n\t\t\tthis.options.value = value;\n\t\t\tthis._refreshValue();\n\t\t\tthis._trigger( \"change\" );\n\t\t\tif ( this._value() === this.max ) {\n\t\t\t\tthis._trigger( \"complete\" );\n\t\t\t}\n\t\t}\n\n\t\t$.Widget.prototype._setOption.apply( this, arguments );\n\t},\n\n\t_value: function() {\n\t\tvar val = this.options.value;\n\t\t// normalize invalid value\n\t\tif ( typeof val !== \"number\" ) {\n\t\t\tval = 0;\n\t\t}\n\t\treturn Math.min( this.max, Math.max( this.min, val ) );\n\t},\n\n\t_refreshValue: function() {\n\t\tvar value = this.value();\n\t\tthis.valueDiv\n\t\t\t.toggleClass( \"ui-corner-right\", value === this.max )\n\t\t\t.width( value + \"%\" );\n\t\tthis.element.attr( \"aria-valuenow\", value );\n\t}\n});\n\n$.extend( $.ui.progressbar, {\n\tversion: \"1.8.6\"\n});\n\n})( jQuery );\n/*\n * jQuery UI Effects 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/\n */\n;jQuery.effects || (function($, undefined) {\n\n$.effects = {};\n\n\n\n/******************************************************************************/\n/****************************** COLOR ANIMATIONS ******************************/\n/******************************************************************************/\n\n// override the animation for color styles\n$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor',\n\t'borderRightColor', 'borderTopColor', 'borderColor', 'color', 'outlineColor'],\nfunction(i, attr) {\n\t$.fx.step[attr] = function(fx) {\n\t\tif (!fx.colorInit) {\n\t\t\tfx.start = getColor(fx.elem, attr);\n\t\t\tfx.end = getRGB(fx.end);\n\t\t\tfx.colorInit = true;\n\t\t}\n\n\t\tfx.elem.style[attr] = 'rgb(' +\n\t\t\tMath.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 255), 0) + ',' +\n\t\t\tMath.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 255), 0) + ',' +\n\t\t\tMath.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 255), 0) + ')';\n\t};\n});\n\n// Color Conversion functions from highlightFade\n// By Blair Mitchelmore\n// http://jquery.offput.ca/highlightFade/\n\n// Parse strings looking for color tuples [255,255,255]\nfunction getRGB(color) {\n\t\tvar result;\n\n\t\t// Check if we're already dealing with an array of colors\n\t\tif ( color && color.constructor == Array && color.length == 3 )\n\t\t\t\treturn color;\n\n\t\t// Look for rgb(num,num,num)\n\t\tif (result = /rgb\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)/.exec(color))\n\t\t\t\treturn [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)];\n\n\t\t// Look for rgb(num%,num%,num%)\n\t\tif (result = /rgb\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)/.exec(color))\n\t\t\t\treturn [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];\n\n\t\t// Look for #a0b1c2\n\t\tif (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))\n\t\t\t\treturn [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];\n\n\t\t// Look for #fff\n\t\tif (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))\n\t\t\t\treturn [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];\n\n\t\t// Look for rgba(0, 0, 0, 0) == transparent in Safari 3\n\t\tif (result = /rgba\\(0, 0, 0, 0\\)/.exec(color))\n\t\t\t\treturn colors['transparent'];\n\n\t\t// Otherwise, we're most likely dealing with a named color\n\t\treturn colors[$.trim(color).toLowerCase()];\n}\n\nfunction getColor(elem, attr) {\n\t\tvar color;\n\n\t\tdo {\n\t\t\t\tcolor = $.curCSS(elem, attr);\n\n\t\t\t\t// Keep going until we find an element that has color, or we hit the body\n\t\t\t\tif ( color != '' && color != 'transparent' || $.nodeName(elem, \"body\") )\n\t\t\t\t\t\tbreak;\n\n\t\t\t\tattr = \"backgroundColor\";\n\t\t} while ( elem = elem.parentNode );\n\n\t\treturn getRGB(color);\n};\n\n// Some named colors to work with\n// From Interface by Stefan Petre\n// http://interface.eyecon.ro/\n\nvar colors = {\n\taqua:[0,255,255],\n\tazure:[240,255,255],\n\tbeige:[245,245,220],\n\tblack:[0,0,0],\n\tblue:[0,0,255],\n\tbrown:[165,42,42],\n\tcyan:[0,255,255],\n\tdarkblue:[0,0,139],\n\tdarkcyan:[0,139,139],\n\tdarkgrey:[169,169,169],\n\tdarkgreen:[0,100,0],\n\tdarkkhaki:[189,183,107],\n\tdarkmagenta:[139,0,139],\n\tdarkolivegreen:[85,107,47],\n\tdarkorange:[255,140,0],\n\tdarkorchid:[153,50,204],\n\tdarkred:[139,0,0],\n\tdarksalmon:[233,150,122],\n\tdarkviolet:[148,0,211],\n\tfuchsia:[255,0,255],\n\tgold:[255,215,0],\n\tgreen:[0,128,0],\n\tindigo:[75,0,130],\n\tkhaki:[240,230,140],\n\tlightblue:[173,216,230],\n\tlightcyan:[224,255,255],\n\tlightgreen:[144,238,144],\n\tlightgrey:[211,211,211],\n\tlightpink:[255,182,193],\n\tlightyellow:[255,255,224],\n\tlime:[0,255,0],\n\tmagenta:[255,0,255],\n\tmaroon:[128,0,0],\n\tnavy:[0,0,128],\n\tolive:[128,128,0],\n\torange:[255,165,0],\n\tpink:[255,192,203],\n\tpurple:[128,0,128],\n\tviolet:[128,0,128],\n\tred:[255,0,0],\n\tsilver:[192,192,192],\n\twhite:[255,255,255],\n\tyellow:[255,255,0],\n\ttransparent: [255,255,255]\n};\n\n\n\n/******************************************************************************/\n/****************************** CLASS ANIMATIONS ******************************/\n/******************************************************************************/\n\nvar classAnimationActions = ['add', 'remove', 'toggle'],\n\tshorthandStyles = {\n\t\tborder: 1,\n\t\tborderBottom: 1,\n\t\tborderColor: 1,\n\t\tborderLeft: 1,\n\t\tborderRight: 1,\n\t\tborderTop: 1,\n\t\tborderWidth: 1,\n\t\tmargin: 1,\n\t\tpadding: 1\n\t};\n\nfunction getElementStyles() {\n\tvar style = document.defaultView\n\t\t\t? document.defaultView.getComputedStyle(this, null)\n\t\t\t: this.currentStyle,\n\t\tnewStyle = {},\n\t\tkey,\n\t\tcamelCase;\n\n\t// webkit enumerates style porperties\n\tif (style && style.length && style[0] && style[style[0]]) {\n\t\tvar len = style.length;\n\t\twhile (len--) {\n\t\t\tkey = style[len];\n\t\t\tif (typeof style[key] == 'string') {\n\t\t\t\tcamelCase = key.replace(/\\-(\\w)/g, function(all, letter){\n\t\t\t\t\treturn letter.toUpperCase();\n\t\t\t\t});\n\t\t\t\tnewStyle[camelCase] = style[key];\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (key in style) {\n\t\t\tif (typeof style[key] === 'string') {\n\t\t\t\tnewStyle[key] = style[key];\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn newStyle;\n}\n\nfunction filterStyles(styles) {\n\tvar name, value;\n\tfor (name in styles) {\n\t\tvalue = styles[name];\n\t\tif (\n\t\t\t// ignore null and undefined values\n\t\t\tvalue == null ||\n\t\t\t// ignore functions (when does this occur?)\n\t\t\t$.isFunction(value) ||\n\t\t\t// shorthand styles that need to be expanded\n\t\t\tname in shorthandStyles ||\n\t\t\t// ignore scrollbars (break in IE)\n\t\t\t(/scrollbar/).test(name) ||\n\n\t\t\t// only colors or values that can be converted to numbers\n\t\t\t(!(/color/i).test(name) && isNaN(parseFloat(value)))\n\t\t) {\n\t\t\tdelete styles[name];\n\t\t}\n\t}\n\t\n\treturn styles;\n}\n\nfunction styleDifference(oldStyle, newStyle) {\n\tvar diff = { _: 0 }, // http://dev.jquery.com/ticket/5459\n\t\tname;\n\n\tfor (name in newStyle) {\n\t\tif (oldStyle[name] != newStyle[name]) {\n\t\t\tdiff[name] = newStyle[name];\n\t\t}\n\t}\n\n\treturn diff;\n}\n\n$.effects.animateClass = function(value, duration, easing, callback) {\n\tif ($.isFunction(easing)) {\n\t\tcallback = easing;\n\t\teasing = null;\n\t}\n\n\treturn this.each(function() {\n\n\t\tvar that = $(this),\n\t\t\toriginalStyleAttr = that.attr('style') || ' ',\n\t\t\toriginalStyle = filterStyles(getElementStyles.call(this)),\n\t\t\tnewStyle,\n\t\t\tclassName = that.attr('className');\n\n\t\t$.each(classAnimationActions, function(i, action) {\n\t\t\tif (value[action]) {\n\t\t\t\tthat[action + 'Class'](value[action]);\n\t\t\t}\n\t\t});\n\t\tnewStyle = filterStyles(getElementStyles.call(this));\n\t\tthat.attr('className', className);\n\n\t\tthat.animate(styleDifference(originalStyle, newStyle), duration, easing, function() {\n\t\t\t$.each(classAnimationActions, function(i, action) {\n\t\t\t\tif (value[action]) { that[action + 'Class'](value[action]); }\n\t\t\t});\n\t\t\t// work around bug in IE by clearing the cssText before setting it\n\t\t\tif (typeof that.attr('style') == 'object') {\n\t\t\t\tthat.attr('style').cssText = '';\n\t\t\t\tthat.attr('style').cssText = originalStyleAttr;\n\t\t\t} else {\n\t\t\t\tthat.attr('style', originalStyleAttr);\n\t\t\t}\n\t\t\tif (callback) { callback.apply(this, arguments); }\n\t\t});\n\t});\n};\n\n$.fn.extend({\n\t_addClass: $.fn.addClass,\n\taddClass: function(classNames, speed, easing, callback) {\n\t\treturn speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames);\n\t},\n\n\t_removeClass: $.fn.removeClass,\n\tremoveClass: function(classNames,speed,easing,callback) {\n\t\treturn speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames);\n\t},\n\n\t_toggleClass: $.fn.toggleClass,\n\ttoggleClass: function(classNames, force, speed, easing, callback) {\n\t\tif ( typeof force == \"boolean\" || force === undefined ) {\n\t\t\tif ( !speed ) {\n\t\t\t\t// without speed parameter;\n\t\t\t\treturn this._toggleClass(classNames, force);\n\t\t\t} else {\n\t\t\t\treturn $.effects.animateClass.apply(this, [(force?{add:classNames}:{remove:classNames}),speed,easing,callback]);\n\t\t\t}\n\t\t} else {\n\t\t\t// without switch parameter;\n\t\t\treturn $.effects.animateClass.apply(this, [{ toggle: classNames },force,speed,easing]);\n\t\t}\n\t},\n\n\tswitchClass: function(remove,add,speed,easing,callback) {\n\t\treturn $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]);\n\t}\n});\n\n\n\n/******************************************************************************/\n/*********************************** EFFECTS **********************************/\n/******************************************************************************/\n\n$.extend($.effects, {\n\tversion: \"1.8.6\",\n\n\t// Saves a set of properties in a data storage\n\tsave: function(element, set) {\n\t\tfor(var i=0; i < set.length; i++) {\n\t\t\tif(set[i] !== null) element.data(\"ec.storage.\"+set[i], element[0].style[set[i]]);\n\t\t}\n\t},\n\n\t// Restores a set of previously saved properties from a data storage\n\trestore: function(element, set) {\n\t\tfor(var i=0; i < set.length; i++) {\n\t\t\tif(set[i] !== null) element.css(set[i], element.data(\"ec.storage.\"+set[i]));\n\t\t}\n\t},\n\n\tsetMode: function(el, mode) {\n\t\tif (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle\n\t\treturn mode;\n\t},\n\n\tgetBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value\n\t\t// this should be a little more flexible in the future to handle a string & hash\n\t\tvar y, x;\n\t\tswitch (origin[0]) {\n\t\t\tcase 'top': y = 0; break;\n\t\t\tcase 'middle': y = 0.5; break;\n\t\t\tcase 'bottom': y = 1; break;\n\t\t\tdefault: y = origin[0] / original.height;\n\t\t};\n\t\tswitch (origin[1]) {\n\t\t\tcase 'left': x = 0; break;\n\t\t\tcase 'center': x = 0.5; break;\n\t\t\tcase 'right': x = 1; break;\n\t\t\tdefault: x = origin[1] / original.width;\n\t\t};\n\t\treturn {x: x, y: y};\n\t},\n\n\t// Wraps the element around a wrapper that copies position properties\n\tcreateWrapper: function(element) {\n\n\t\t// if the element is already wrapped, return it\n\t\tif (element.parent().is('.ui-effects-wrapper')) {\n\t\t\treturn element.parent();\n\t\t}\n\n\t\t// wrap the element\n\t\tvar props = {\n\t\t\t\twidth: element.outerWidth(true),\n\t\t\t\theight: element.outerHeight(true),\n\t\t\t\t'float': element.css('float')\n\t\t\t},\n\t\t\twrapper = $('<div></div>')\n\t\t\t\t.addClass('ui-effects-wrapper')\n\t\t\t\t.css({\n\t\t\t\t\tfontSize: '100%',\n\t\t\t\t\tbackground: 'transparent',\n\t\t\t\t\tborder: 'none',\n\t\t\t\t\tmargin: 0,\n\t\t\t\t\tpadding: 0\n\t\t\t\t});\n\n\t\telement.wrap(wrapper);\n\t\twrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element\n\n\t\t// transfer positioning properties to the wrapper\n\t\tif (element.css('position') == 'static') {\n\t\t\twrapper.css({ position: 'relative' });\n\t\t\telement.css({ position: 'relative' });\n\t\t} else {\n\t\t\t$.extend(props, {\n\t\t\t\tposition: element.css('position'),\n\t\t\t\tzIndex: element.css('z-index')\n\t\t\t});\n\t\t\t$.each(['top', 'left', 'bottom', 'right'], function(i, pos) {\n\t\t\t\tprops[pos] = element.css(pos);\n\t\t\t\tif (isNaN(parseInt(props[pos], 10))) {\n\t\t\t\t\tprops[pos] = 'auto';\n\t\t\t\t}\n\t\t\t});\n\t\t\telement.css({position: 'relative', top: 0, left: 0 });\n\t\t}\n\n\t\treturn wrapper.css(props).show();\n\t},\n\n\tremoveWrapper: function(element) {\n\t\tif (element.parent().is('.ui-effects-wrapper'))\n\t\t\treturn element.parent().replaceWith(element);\n\t\treturn element;\n\t},\n\n\tsetTransition: function(element, list, factor, value) {\n\t\tvalue = value || {};\n\t\t$.each(list, function(i, x){\n\t\t\tunit = element.cssUnit(x);\n\t\t\tif (unit[0] > 0) value[x] = unit[0] * factor + unit[1];\n\t\t});\n\t\treturn value;\n\t}\n});\n\n\nfunction _normalizeArguments(effect, options, speed, callback) {\n\t// shift params for method overloading\n\tif (typeof effect == 'object') {\n\t\tcallback = options;\n\t\tspeed = null;\n\t\toptions = effect;\n\t\teffect = options.effect;\n\t}\n\tif ($.isFunction(options)) {\n\t\tcallback = options;\n\t\tspeed = null;\n\t\toptions = {};\n\t}\n        if (typeof options == 'number' || $.fx.speeds[options]) {\n\t\tcallback = speed;\n\t\tspeed = options;\n\t\toptions = {};\n\t}\n\tif ($.isFunction(speed)) {\n\t\tcallback = speed;\n\t\tspeed = null;\n\t}\n\n\toptions = options || {};\n\n\tspeed = speed || options.duration;\n\tspeed = $.fx.off ? 0 : typeof speed == 'number'\n\t\t? speed : $.fx.speeds[speed] || $.fx.speeds._default;\n\n\tcallback = callback || options.complete;\n\n\treturn [effect, options, speed, callback];\n}\n\nfunction standardSpeed( speed ) {\n\t// valid standard speeds\n\tif ( !speed || typeof speed === \"number\" || $.fx.speeds[ speed ] ) {\n\t\treturn true;\n\t}\n\t\n\t// invalid strings - treat as \"normal\" speed\n\tif ( typeof speed === \"string\" && !$.effects[ speed ] ) {\n\t\treturn true;\n\t}\n\t\n\treturn false;\n}\n\n$.fn.extend({\n\teffect: function(effect, options, speed, callback) {\n\t\tvar args = _normalizeArguments.apply(this, arguments),\n\t\t\t// TODO: make effects take actual parameters instead of a hash\n\t\t\targs2 = {\n\t\t\t\toptions: args[1],\n\t\t\t\tduration: args[2],\n\t\t\t\tcallback: args[3]\n\t\t\t},\n\t\t\tmode = args2.options.mode,\n\t\t\teffectMethod = $.effects[effect];\n\t\t\n\t\tif ( $.fx.off || !effectMethod ) {\n\t\t\t// delegate to the original method (e.g., .show()) if possible\n\t\t\tif ( mode ) {\n\t\t\t\treturn this[ mode ]( args2.duration, args2.callback );\n\t\t\t} else {\n\t\t\t\treturn this.each(function() {\n\t\t\t\t\tif ( args2.callback ) {\n\t\t\t\t\t\targs2.callback.call( this );\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn effectMethod.call(this, args2);\n\t},\n\n\t_show: $.fn.show,\n\tshow: function(speed) {\n\t\tif ( standardSpeed( speed ) ) {\n\t\t\treturn this._show.apply(this, arguments);\n\t\t} else {\n\t\t\tvar args = _normalizeArguments.apply(this, arguments);\n\t\t\targs[1].mode = 'show';\n\t\t\treturn this.effect.apply(this, args);\n\t\t}\n\t},\n\n\t_hide: $.fn.hide,\n\thide: function(speed) {\n\t\tif ( standardSpeed( speed ) ) {\n\t\t\treturn this._hide.apply(this, arguments);\n\t\t} else {\n\t\t\tvar args = _normalizeArguments.apply(this, arguments);\n\t\t\targs[1].mode = 'hide';\n\t\t\treturn this.effect.apply(this, args);\n\t\t}\n\t},\n\n\t// jQuery core overloads toggle and creates _toggle\n\t__toggle: $.fn.toggle,\n\ttoggle: function(speed) {\n\t\tif ( standardSpeed( speed ) || typeof speed === \"boolean\" || $.isFunction( speed ) ) {\n\t\t\treturn this.__toggle.apply(this, arguments);\n\t\t} else {\n\t\t\tvar args = _normalizeArguments.apply(this, arguments);\n\t\t\targs[1].mode = 'toggle';\n\t\t\treturn this.effect.apply(this, args);\n\t\t}\n\t},\n\n\t// helper functions\n\tcssUnit: function(key) {\n\t\tvar style = this.css(key), val = [];\n\t\t$.each( ['em','px','%','pt'], function(i, unit){\n\t\t\tif(style.indexOf(unit) > 0)\n\t\t\t\tval = [parseFloat(style), unit];\n\t\t});\n\t\treturn val;\n\t}\n});\n\n\n\n/******************************************************************************/\n/*********************************** EASING ***********************************/\n/******************************************************************************/\n\n/*\n * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/\n *\n * Uses the built in easing capabilities added In jQuery 1.1\n * to offer multiple easing options\n *\n * TERMS OF USE - jQuery Easing\n *\n * Open source under the BSD License.\n *\n * Copyright 2008 George McGinley Smith\n * All rights reserved.\n *\n * Redistribution and use 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 copyright notice, this list of\n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list\n * of conditions and the following disclaimer in the documentation and/or other materials\n * provided with the distribution.\n *\n * Neither the name of the author nor the names of contributors may be used to endorse\n * or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n*/\n\n// t: current time, b: begInnIng value, c: change In value, d: duration\n$.easing.jswing = $.easing.swing;\n\n$.extend($.easing,\n{\n\tdef: 'easeOutQuad',\n\tswing: function (x, t, b, c, d) {\n\t\t//alert($.easing.default);\n\t\treturn $.easing[$.easing.def](x, t, b, c, d);\n\t},\n\teaseInQuad: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t + b;\n\t},\n\teaseOutQuad: function (x, t, b, c, d) {\n\t\treturn -c *(t/=d)*(t-2) + b;\n\t},\n\teaseInOutQuad: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t + b;\n\t\treturn -c/2 * ((--t)*(t-2) - 1) + b;\n\t},\n\teaseInCubic: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t*t + b;\n\t},\n\teaseOutCubic: function (x, t, b, c, d) {\n\t\treturn c*((t=t/d-1)*t*t + 1) + b;\n\t},\n\teaseInOutCubic: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t*t + b;\n\t\treturn c/2*((t-=2)*t*t + 2) + b;\n\t},\n\teaseInQuart: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t*t*t + b;\n\t},\n\teaseOutQuart: function (x, t, b, c, d) {\n\t\treturn -c * ((t=t/d-1)*t*t*t - 1) + b;\n\t},\n\teaseInOutQuart: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t*t*t + b;\n\t\treturn -c/2 * ((t-=2)*t*t*t - 2) + b;\n\t},\n\teaseInQuint: function (x, t, b, c, d) {\n\t\treturn c*(t/=d)*t*t*t*t + b;\n\t},\n\teaseOutQuint: function (x, t, b, c, d) {\n\t\treturn c*((t=t/d-1)*t*t*t*t + 1) + b;\n\t},\n\teaseInOutQuint: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;\n\t\treturn c/2*((t-=2)*t*t*t*t + 2) + b;\n\t},\n\teaseInSine: function (x, t, b, c, d) {\n\t\treturn -c * Math.cos(t/d * (Math.PI/2)) + c + b;\n\t},\n\teaseOutSine: function (x, t, b, c, d) {\n\t\treturn c * Math.sin(t/d * (Math.PI/2)) + b;\n\t},\n\teaseInOutSine: function (x, t, b, c, d) {\n\t\treturn -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;\n\t},\n\teaseInExpo: function (x, t, b, c, d) {\n\t\treturn (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;\n\t},\n\teaseOutExpo: function (x, t, b, c, d) {\n\t\treturn (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;\n\t},\n\teaseInOutExpo: function (x, t, b, c, d) {\n\t\tif (t==0) return b;\n\t\tif (t==d) return b+c;\n\t\tif ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;\n\t\treturn c/2 * (-Math.pow(2, -10 * --t) + 2) + b;\n\t},\n\teaseInCirc: function (x, t, b, c, d) {\n\t\treturn -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;\n\t},\n\teaseOutCirc: function (x, t, b, c, d) {\n\t\treturn c * Math.sqrt(1 - (t=t/d-1)*t) + b;\n\t},\n\teaseInOutCirc: function (x, t, b, c, d) {\n\t\tif ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;\n\t\treturn c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;\n\t},\n\teaseInElastic: function (x, t, b, c, d) {\n\t\tvar s=1.70158;var p=0;var a=c;\n\t\tif (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;\n\t\tif (a < Math.abs(c)) { a=c; var s=p/4; }\n\t\telse var s = p/(2*Math.PI) * Math.asin (c/a);\n\t\treturn -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;\n\t},\n\teaseOutElastic: function (x, t, b, c, d) {\n\t\tvar s=1.70158;var p=0;var a=c;\n\t\tif (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;\n\t\tif (a < Math.abs(c)) { a=c; var s=p/4; }\n\t\telse var s = p/(2*Math.PI) * Math.asin (c/a);\n\t\treturn a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;\n\t},\n\teaseInOutElastic: function (x, t, b, c, d) {\n\t\tvar s=1.70158;var p=0;var a=c;\n\t\tif (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);\n\t\tif (a < Math.abs(c)) { a=c; var s=p/4; }\n\t\telse var s = p/(2*Math.PI) * Math.asin (c/a);\n\t\tif (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;\n\t\treturn a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;\n\t},\n\teaseInBack: function (x, t, b, c, d, s) {\n\t\tif (s == undefined) s = 1.70158;\n\t\treturn c*(t/=d)*t*((s+1)*t - s) + b;\n\t},\n\teaseOutBack: function (x, t, b, c, d, s) {\n\t\tif (s == undefined) s = 1.70158;\n\t\treturn c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;\n\t},\n\teaseInOutBack: function (x, t, b, c, d, s) {\n\t\tif (s == undefined) s = 1.70158;\n\t\tif ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;\n\t\treturn c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;\n\t},\n\teaseInBounce: function (x, t, b, c, d) {\n\t\treturn c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b;\n\t},\n\teaseOutBounce: function (x, t, b, c, d) {\n\t\tif ((t/=d) < (1/2.75)) {\n\t\t\treturn c*(7.5625*t*t) + b;\n\t\t} else if (t < (2/2.75)) {\n\t\t\treturn c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;\n\t\t} else if (t < (2.5/2.75)) {\n\t\t\treturn c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;\n\t\t} else {\n\t\t\treturn c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;\n\t\t}\n\t},\n\teaseInOutBounce: function (x, t, b, c, d) {\n\t\tif (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;\n\t\treturn $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;\n\t}\n});\n\n/*\n *\n * TERMS OF USE - EASING EQUATIONS\n *\n * Open source under the BSD License.\n *\n * Copyright 2001 Robert Penner\n * All rights reserved.\n *\n * Redistribution and use 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 copyright notice, this list of\n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list\n * of conditions and the following disclaimer in the documentation and/or other materials\n * provided with the distribution.\n *\n * Neither the name of the author nor the names of contributors may be used to endorse\n * or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n})(jQuery);\n/*\n * jQuery UI Effects Blind 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Blind\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.blind = function(o) {\n\n\treturn this.queue(function() {\n\n\t\t// Create element\n\t\tvar el = $(this), props = ['position','top','left'];\n\n\t\t// Set options\n\t\tvar mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode\n\t\tvar direction = o.options.direction || 'vertical'; // Default direction\n\n\t\t// Adjust\n\t\t$.effects.save(el, props); el.show(); // Save & Show\n\t\tvar wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper\n\t\tvar ref = (direction == 'vertical') ? 'height' : 'width';\n\t\tvar distance = (direction == 'vertical') ? wrapper.height() : wrapper.width();\n\t\tif(mode == 'show') wrapper.css(ref, 0); // Shift\n\n\t\t// Animation\n\t\tvar animation = {};\n\t\tanimation[ref] = mode == 'show' ? distance : 0;\n\n\t\t// Animate\n\t\twrapper.animate(animation, o.duration, o.options.easing, function() {\n\t\t\tif(mode == 'hide') el.hide(); // Hide\n\t\t\t$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore\n\t\t\tif(o.callback) o.callback.apply(el[0], arguments); // Callback\n\t\t\tel.dequeue();\n\t\t});\n\n\t});\n\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Bounce 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Bounce\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.bounce = function(o) {\n\n\treturn this.queue(function() {\n\n\t\t// Create element\n\t\tvar el = $(this), props = ['position','top','left'];\n\n\t\t// Set options\n\t\tvar mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode\n\t\tvar direction = o.options.direction || 'up'; // Default direction\n\t\tvar distance = o.options.distance || 20; // Default distance\n\t\tvar times = o.options.times || 5; // Default # of times\n\t\tvar speed = o.duration || 250; // Default speed per bounce\n\t\tif (/show|hide/.test(mode)) props.push('opacity'); // Avoid touching opacity to prevent clearType and PNG issues in IE\n\n\t\t// Adjust\n\t\t$.effects.save(el, props); el.show(); // Save & Show\n\t\t$.effects.createWrapper(el); // Create Wrapper\n\t\tvar ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';\n\t\tvar motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';\n\t\tvar distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 3 : el.outerWidth({margin:true}) / 3);\n\t\tif (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift\n\t\tif (mode == 'hide') distance = distance / (times * 2);\n\t\tif (mode != 'hide') times--;\n\n\t\t// Animate\n\t\tif (mode == 'show') { // Show Bounce\n\t\t\tvar animation = {opacity: 1};\n\t\t\tanimation[ref] = (motion == 'pos' ? '+=' : '-=') + distance;\n\t\t\tel.animate(animation, speed / 2, o.options.easing);\n\t\t\tdistance = distance / 2;\n\t\t\ttimes--;\n\t\t};\n\t\tfor (var i = 0; i < times; i++) { // Bounces\n\t\t\tvar animation1 = {}, animation2 = {};\n\t\t\tanimation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;\n\t\t\tanimation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;\n\t\t\tel.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing);\n\t\t\tdistance = (mode == 'hide') ? distance * 2 : distance / 2;\n\t\t};\n\t\tif (mode == 'hide') { // Last Bounce\n\t\t\tvar animation = {opacity: 0};\n\t\t\tanimation[ref] = (motion == 'pos' ? '-=' : '+=')  + distance;\n\t\t\tel.animate(animation, speed / 2, o.options.easing, function(){\n\t\t\t\tel.hide(); // Hide\n\t\t\t\t$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore\n\t\t\t\tif(o.callback) o.callback.apply(this, arguments); // Callback\n\t\t\t});\n\t\t} else {\n\t\t\tvar animation1 = {}, animation2 = {};\n\t\t\tanimation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;\n\t\t\tanimation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;\n\t\t\tel.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing, function(){\n\t\t\t\t$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore\n\t\t\t\tif(o.callback) o.callback.apply(this, arguments); // Callback\n\t\t\t});\n\t\t};\n\t\tel.queue('fx', function() { el.dequeue(); });\n\t\tel.dequeue();\n\t});\n\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Clip 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Clip\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.clip = function(o) {\n\n\treturn this.queue(function() {\n\n\t\t// Create element\n\t\tvar el = $(this), props = ['position','top','left','height','width'];\n\n\t\t// Set options\n\t\tvar mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode\n\t\tvar direction = o.options.direction || 'vertical'; // Default direction\n\n\t\t// Adjust\n\t\t$.effects.save(el, props); el.show(); // Save & Show\n\t\tvar wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper\n\t\tvar animate = el[0].tagName == 'IMG' ? wrapper : el;\n\t\tvar ref = {\n\t\t\tsize: (direction == 'vertical') ? 'height' : 'width',\n\t\t\tposition: (direction == 'vertical') ? 'top' : 'left'\n\t\t};\n\t\tvar distance = (direction == 'vertical') ? animate.height() : animate.width();\n\t\tif(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift\n\n\t\t// Animation\n\t\tvar animation = {};\n\t\tanimation[ref.size] = mode == 'show' ? distance : 0;\n\t\tanimation[ref.position] = mode == 'show' ? 0 : distance / 2;\n\n\t\t// Animate\n\t\tanimate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {\n\t\t\tif(mode == 'hide') el.hide(); // Hide\n\t\t\t$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore\n\t\t\tif(o.callback) o.callback.apply(el[0], arguments); // Callback\n\t\t\tel.dequeue();\n\t\t}});\n\n\t});\n\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Drop 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Drop\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.drop = function(o) {\n\n\treturn this.queue(function() {\n\n\t\t// Create element\n\t\tvar el = $(this), props = ['position','top','left','opacity'];\n\n\t\t// Set options\n\t\tvar mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode\n\t\tvar direction = o.options.direction || 'left'; // Default Direction\n\n\t\t// Adjust\n\t\t$.effects.save(el, props); el.show(); // Save & Show\n\t\t$.effects.createWrapper(el); // Create Wrapper\n\t\tvar ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';\n\t\tvar motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';\n\t\tvar distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2);\n\t\tif (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift\n\n\t\t// Animation\n\t\tvar animation = {opacity: mode == 'show' ? 1 : 0};\n\t\tanimation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;\n\n\t\t// Animate\n\t\tel.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {\n\t\t\tif(mode == 'hide') el.hide(); // Hide\n\t\t\t$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore\n\t\t\tif(o.callback) o.callback.apply(this, arguments); // Callback\n\t\t\tel.dequeue();\n\t\t}});\n\n\t});\n\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Explode 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Explode\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.explode = function(o) {\n\n\treturn this.queue(function() {\n\n\tvar rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;\n\tvar cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;\n\n\to.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode;\n\tvar el = $(this).show().css('visibility', 'hidden');\n\tvar offset = el.offset();\n\n\t//Substract the margins - not fixing the problem yet.\n\toffset.top -= parseInt(el.css(\"marginTop\"),10) || 0;\n\toffset.left -= parseInt(el.css(\"marginLeft\"),10) || 0;\n\n\tvar width = el.outerWidth(true);\n\tvar height = el.outerHeight(true);\n\n\tfor(var i=0;i<rows;i++) { // =\n\t\tfor(var j=0;j<cells;j++) { // ||\n\t\t\tel\n\t\t\t\t.clone()\n\t\t\t\t.appendTo('body')\n\t\t\t\t.wrap('<div></div>')\n\t\t\t\t.css({\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\tvisibility: 'visible',\n\t\t\t\t\tleft: -j*(width/cells),\n\t\t\t\t\ttop: -i*(height/rows)\n\t\t\t\t})\n\t\t\t\t.parent()\n\t\t\t\t.addClass('ui-effects-explode')\n\t\t\t\t.css({\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\twidth: width/cells,\n\t\t\t\t\theight: height/rows,\n\t\t\t\t\tleft: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0),\n\t\t\t\t\ttop: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0),\n\t\t\t\t\topacity: o.options.mode == 'show' ? 0 : 1\n\t\t\t\t}).animate({\n\t\t\t\t\tleft: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)),\n\t\t\t\t\ttop: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)),\n\t\t\t\t\topacity: o.options.mode == 'show' ? 1 : 0\n\t\t\t\t}, o.duration || 500);\n\t\t}\n\t}\n\n\t// Set a timeout, to call the callback approx. when the other animations have finished\n\tsetTimeout(function() {\n\n\t\to.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide();\n\t\t\t\tif(o.callback) o.callback.apply(el[0]); // Callback\n\t\t\t\tel.dequeue();\n\n\t\t\t\t$('div.ui-effects-explode').remove();\n\n\t}, o.duration || 500);\n\n\n\t});\n\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Fade 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Fade\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.fade = function(o) {\n\treturn this.queue(function() {\n\t\tvar elem = $(this),\n\t\t\tmode = $.effects.setMode(elem, o.options.mode || 'hide');\n\n\t\telem.animate({ opacity: mode }, {\n\t\t\tqueue: false,\n\t\t\tduration: o.duration,\n\t\t\teasing: o.options.easing,\n\t\t\tcomplete: function() {\n\t\t\t\t(o.callback && o.callback.apply(this, arguments));\n\t\t\t\telem.dequeue();\n\t\t\t}\n\t\t});\n\t});\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Fold 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Fold\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.fold = function(o) {\n\n\treturn this.queue(function() {\n\n\t\t// Create element\n\t\tvar el = $(this), props = ['position','top','left'];\n\n\t\t// Set options\n\t\tvar mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode\n\t\tvar size = o.options.size || 15; // Default fold size\n\t\tvar horizFirst = !(!o.options.horizFirst); // Ensure a boolean value\n\t\tvar duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2;\n\n\t\t// Adjust\n\t\t$.effects.save(el, props); el.show(); // Save & Show\n\t\tvar wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper\n\t\tvar widthFirst = ((mode == 'show') != horizFirst);\n\t\tvar ref = widthFirst ? ['width', 'height'] : ['height', 'width'];\n\t\tvar distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()];\n\t\tvar percent = /([0-9]+)%/.exec(size);\n\t\tif(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1];\n\t\tif(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift\n\n\t\t// Animation\n\t\tvar animation1 = {}, animation2 = {};\n\t\tanimation1[ref[0]] = mode == 'show' ? distance[0] : size;\n\t\tanimation2[ref[1]] = mode == 'show' ? distance[1] : 0;\n\n\t\t// Animate\n\t\twrapper.animate(animation1, duration, o.options.easing)\n\t\t.animate(animation2, duration, o.options.easing, function() {\n\t\t\tif(mode == 'hide') el.hide(); // Hide\n\t\t\t$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore\n\t\t\tif(o.callback) o.callback.apply(el[0], arguments); // Callback\n\t\t\tel.dequeue();\n\t\t});\n\n\t});\n\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Highlight 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Highlight\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.highlight = function(o) {\n\treturn this.queue(function() {\n\t\tvar elem = $(this),\n\t\t\tprops = ['backgroundImage', 'backgroundColor', 'opacity'],\n\t\t\tmode = $.effects.setMode(elem, o.options.mode || 'show'),\n\t\t\tanimation = {\n\t\t\t\tbackgroundColor: elem.css('backgroundColor')\n\t\t\t};\n\n\t\tif (mode == 'hide') {\n\t\t\tanimation.opacity = 0;\n\t\t}\n\n\t\t$.effects.save(elem, props);\n\t\telem\n\t\t\t.show()\n\t\t\t.css({\n\t\t\t\tbackgroundImage: 'none',\n\t\t\t\tbackgroundColor: o.options.color || '#ffff99'\n\t\t\t})\n\t\t\t.animate(animation, {\n\t\t\t\tqueue: false,\n\t\t\t\tduration: o.duration,\n\t\t\t\teasing: o.options.easing,\n\t\t\t\tcomplete: function() {\n\t\t\t\t\t(mode == 'hide' && elem.hide());\n\t\t\t\t\t$.effects.restore(elem, props);\n\t\t\t\t\t(mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter'));\n\t\t\t\t\t(o.callback && o.callback.apply(this, arguments));\n\t\t\t\t\telem.dequeue();\n\t\t\t\t}\n\t\t\t});\n\t});\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Pulsate 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Pulsate\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.pulsate = function(o) {\n\treturn this.queue(function() {\n\t\tvar elem = $(this),\n\t\t\tmode = $.effects.setMode(elem, o.options.mode || 'show');\n\t\t\ttimes = ((o.options.times || 5) * 2) - 1;\n\t\t\tduration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2,\n\t\t\tisVisible = elem.is(':visible'),\n\t\t\tanimateTo = 0;\n\n\t\tif (!isVisible) {\n\t\t\telem.css('opacity', 0).show();\n\t\t\tanimateTo = 1;\n\t\t}\n\n\t\tif ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) {\n\t\t\ttimes--;\n\t\t}\n\n\t\tfor (var i = 0; i < times; i++) {\n\t\t\telem.animate({ opacity: animateTo }, duration, o.options.easing);\n\t\t\tanimateTo = (animateTo + 1) % 2;\n\t\t}\n\n\t\telem.animate({ opacity: animateTo }, duration, o.options.easing, function() {\n\t\t\tif (animateTo == 0) {\n\t\t\t\telem.hide();\n\t\t\t}\n\t\t\t(o.callback && o.callback.apply(this, arguments));\n\t\t});\n\n\t\telem\n\t\t\t.queue('fx', function() { elem.dequeue(); })\n\t\t\t.dequeue();\n\t});\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Scale 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Scale\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.puff = function(o) {\n\treturn this.queue(function() {\n\t\tvar elem = $(this),\n\t\t\tmode = $.effects.setMode(elem, o.options.mode || 'hide'),\n\t\t\tpercent = parseInt(o.options.percent, 10) || 150,\n\t\t\tfactor = percent / 100,\n\t\t\toriginal = { height: elem.height(), width: elem.width() };\n\n\t\t$.extend(o.options, {\n\t\t\tfade: true,\n\t\t\tmode: mode,\n\t\t\tpercent: mode == 'hide' ? percent : 100,\n\t\t\tfrom: mode == 'hide'\n\t\t\t\t? original\n\t\t\t\t: {\n\t\t\t\t\theight: original.height * factor,\n\t\t\t\t\twidth: original.width * factor\n\t\t\t\t}\n\t\t});\n\n\t\telem.effect('scale', o.options, o.duration, o.callback);\n\t\telem.dequeue();\n\t});\n};\n\n$.effects.scale = function(o) {\n\n\treturn this.queue(function() {\n\n\t\t// Create element\n\t\tvar el = $(this);\n\n\t\t// Set options\n\t\tvar options = $.extend(true, {}, o.options);\n\t\tvar mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode\n\t\tvar percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent\n\t\tvar direction = o.options.direction || 'both'; // Set default axis\n\t\tvar origin = o.options.origin; // The origin of the scaling\n\t\tif (mode != 'effect') { // Set default origin and restore for show/hide\n\t\t\toptions.origin = origin || ['middle','center'];\n\t\t\toptions.restore = true;\n\t\t}\n\t\tvar original = {height: el.height(), width: el.width()}; // Save original\n\t\tel.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state\n\n\t\t// Adjust\n\t\tvar factor = { // Set scaling factor\n\t\t\ty: direction != 'horizontal' ? (percent / 100) : 1,\n\t\t\tx: direction != 'vertical' ? (percent / 100) : 1\n\t\t};\n\t\tel.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state\n\n\t\tif (o.options.fade) { // Fade option to support puff\n\t\t\tif (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;};\n\t\t\tif (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;};\n\t\t};\n\n\t\t// Animation\n\t\toptions.from = el.from; options.to = el.to; options.mode = mode;\n\n\t\t// Animate\n\t\tel.effect('size', options, o.duration, o.callback);\n\t\tel.dequeue();\n\t});\n\n};\n\n$.effects.size = function(o) {\n\n\treturn this.queue(function() {\n\n\t\t// Create element\n\t\tvar el = $(this), props = ['position','top','left','width','height','overflow','opacity'];\n\t\tvar props1 = ['position','top','left','overflow','opacity']; // Always restore\n\t\tvar props2 = ['width','height','overflow']; // Copy for children\n\t\tvar cProps = ['fontSize'];\n\t\tvar vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom'];\n\t\tvar hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight'];\n\n\t\t// Set options\n\t\tvar mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode\n\t\tvar restore = o.options.restore || false; // Default restore\n\t\tvar scale = o.options.scale || 'both'; // Default scale mode\n\t\tvar origin = o.options.origin; // The origin of the sizing\n\t\tvar original = {height: el.height(), width: el.width()}; // Save original\n\t\tel.from = o.options.from || original; // Default from state\n\t\tel.to = o.options.to || original; // Default to state\n\t\t// Adjust\n\t\tif (origin) { // Calculate baseline shifts\n\t\t\tvar baseline = $.effects.getBaseline(origin, original);\n\t\t\tel.from.top = (original.height - el.from.height) * baseline.y;\n\t\t\tel.from.left = (original.width - el.from.width) * baseline.x;\n\t\t\tel.to.top = (original.height - el.to.height) * baseline.y;\n\t\t\tel.to.left = (original.width - el.to.width) * baseline.x;\n\t\t};\n\t\tvar factor = { // Set scaling factor\n\t\t\tfrom: {y: el.from.height / original.height, x: el.from.width / original.width},\n\t\t\tto: {y: el.to.height / original.height, x: el.to.width / original.width}\n\t\t};\n\t\tif (scale == 'box' || scale == 'both') { // Scale the css box\n\t\t\tif (factor.from.y != factor.to.y) { // Vertical props scaling\n\t\t\t\tprops = props.concat(vProps);\n\t\t\t\tel.from = $.effects.setTransition(el, vProps, factor.from.y, el.from);\n\t\t\t\tel.to = $.effects.setTransition(el, vProps, factor.to.y, el.to);\n\t\t\t};\n\t\t\tif (factor.from.x != factor.to.x) { // Horizontal props scaling\n\t\t\t\tprops = props.concat(hProps);\n\t\t\t\tel.from = $.effects.setTransition(el, hProps, factor.from.x, el.from);\n\t\t\t\tel.to = $.effects.setTransition(el, hProps, factor.to.x, el.to);\n\t\t\t};\n\t\t};\n\t\tif (scale == 'content' || scale == 'both') { // Scale the content\n\t\t\tif (factor.from.y != factor.to.y) { // Vertical props scaling\n\t\t\t\tprops = props.concat(cProps);\n\t\t\t\tel.from = $.effects.setTransition(el, cProps, factor.from.y, el.from);\n\t\t\t\tel.to = $.effects.setTransition(el, cProps, factor.to.y, el.to);\n\t\t\t};\n\t\t};\n\t\t$.effects.save(el, restore ? props : props1); el.show(); // Save & Show\n\t\t$.effects.createWrapper(el); // Create Wrapper\n\t\tel.css('overflow','hidden').css(el.from); // Shift\n\n\t\t// Animate\n\t\tif (scale == 'content' || scale == 'both') { // Scale the children\n\t\t\tvProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size\n\t\t\thProps = hProps.concat(['marginLeft','marginRight']); // Add margins\n\t\t\tprops2 = props.concat(vProps).concat(hProps); // Concat\n\t\t\tel.find(\"*[width]\").each(function(){\n\t\t\t\tchild = $(this);\n\t\t\t\tif (restore) $.effects.save(child, props2);\n\t\t\t\tvar c_original = {height: child.height(), width: child.width()}; // Save original\n\t\t\t\tchild.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x};\n\t\t\t\tchild.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x};\n\t\t\t\tif (factor.from.y != factor.to.y) { // Vertical props scaling\n\t\t\t\t\tchild.from = $.effects.setTransition(child, vProps, factor.from.y, child.from);\n\t\t\t\t\tchild.to = $.effects.setTransition(child, vProps, factor.to.y, child.to);\n\t\t\t\t};\n\t\t\t\tif (factor.from.x != factor.to.x) { // Horizontal props scaling\n\t\t\t\t\tchild.from = $.effects.setTransition(child, hProps, factor.from.x, child.from);\n\t\t\t\t\tchild.to = $.effects.setTransition(child, hProps, factor.to.x, child.to);\n\t\t\t\t};\n\t\t\t\tchild.css(child.from); // Shift children\n\t\t\t\tchild.animate(child.to, o.duration, o.options.easing, function(){\n\t\t\t\t\tif (restore) $.effects.restore(child, props2); // Restore children\n\t\t\t\t}); // Animate children\n\t\t\t});\n\t\t};\n\n\t\t// Animate\n\t\tel.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {\n\t\t\tif (el.to.opacity === 0) {\n\t\t\t\tel.css('opacity', el.from.opacity);\n\t\t\t}\n\t\t\tif(mode == 'hide') el.hide(); // Hide\n\t\t\t$.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore\n\t\t\tif(o.callback) o.callback.apply(this, arguments); // Callback\n\t\t\tel.dequeue();\n\t\t}});\n\n\t});\n\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Shake 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Shake\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.shake = function(o) {\n\n\treturn this.queue(function() {\n\n\t\t// Create element\n\t\tvar el = $(this), props = ['position','top','left'];\n\n\t\t// Set options\n\t\tvar mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode\n\t\tvar direction = o.options.direction || 'left'; // Default direction\n\t\tvar distance = o.options.distance || 20; // Default distance\n\t\tvar times = o.options.times || 3; // Default # of times\n\t\tvar speed = o.duration || o.options.duration || 140; // Default speed per shake\n\n\t\t// Adjust\n\t\t$.effects.save(el, props); el.show(); // Save & Show\n\t\t$.effects.createWrapper(el); // Create Wrapper\n\t\tvar ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';\n\t\tvar motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';\n\n\t\t// Animation\n\t\tvar animation = {}, animation1 = {}, animation2 = {};\n\t\tanimation[ref] = (motion == 'pos' ? '-=' : '+=')  + distance;\n\t\tanimation1[ref] = (motion == 'pos' ? '+=' : '-=')  + distance * 2;\n\t\tanimation2[ref] = (motion == 'pos' ? '-=' : '+=')  + distance * 2;\n\n\t\t// Animate\n\t\tel.animate(animation, speed, o.options.easing);\n\t\tfor (var i = 1; i < times; i++) { // Shakes\n\t\t\tel.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing);\n\t\t};\n\t\tel.animate(animation1, speed, o.options.easing).\n\t\tanimate(animation, speed / 2, o.options.easing, function(){ // Last shake\n\t\t\t$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore\n\t\t\tif(o.callback) o.callback.apply(this, arguments); // Callback\n\t\t});\n\t\tel.queue('fx', function() { el.dequeue(); });\n\t\tel.dequeue();\n\t});\n\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Slide 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Slide\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.slide = function(o) {\n\n\treturn this.queue(function() {\n\n\t\t// Create element\n\t\tvar el = $(this), props = ['position','top','left'];\n\n\t\t// Set options\n\t\tvar mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode\n\t\tvar direction = o.options.direction || 'left'; // Default Direction\n\n\t\t// Adjust\n\t\t$.effects.save(el, props); el.show(); // Save & Show\n\t\t$.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper\n\t\tvar ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';\n\t\tvar motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';\n\t\tvar distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true}));\n\t\tif (mode == 'show') el.css(ref, motion == 'pos' ? -distance : distance); // Shift\n\n\t\t// Animation\n\t\tvar animation = {};\n\t\tanimation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;\n\n\t\t// Animate\n\t\tel.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {\n\t\t\tif(mode == 'hide') el.hide(); // Hide\n\t\t\t$.effects.restore(el, props); $.effects.removeWrapper(el); // Restore\n\t\t\tif(o.callback) o.callback.apply(this, arguments); // Callback\n\t\t\tel.dequeue();\n\t\t}});\n\n\t});\n\n};\n\n})(jQuery);\n/*\n * jQuery UI Effects Transfer 1.8.6\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Transfer\n *\n * Depends:\n *\tjquery.effects.core.js\n */\n(function( $, undefined ) {\n\n$.effects.transfer = function(o) {\n\treturn this.queue(function() {\n\t\tvar elem = $(this),\n\t\t\ttarget = $(o.options.to),\n\t\t\tendPosition = target.offset(),\n\t\t\tanimation = {\n\t\t\t\ttop: endPosition.top,\n\t\t\t\tleft: endPosition.left,\n\t\t\t\theight: target.innerHeight(),\n\t\t\t\twidth: target.innerWidth()\n\t\t\t},\n\t\t\tstartPosition = elem.offset(),\n\t\t\ttransfer = $('<div class=\"ui-effects-transfer\"></div>')\n\t\t\t\t.appendTo(document.body)\n\t\t\t\t.addClass(o.options.className)\n\t\t\t\t.css({\n\t\t\t\t\ttop: startPosition.top,\n\t\t\t\t\tleft: startPosition.left,\n\t\t\t\t\theight: elem.innerHeight(),\n\t\t\t\t\twidth: elem.innerWidth(),\n\t\t\t\t\tposition: 'absolute'\n\t\t\t\t})\n\t\t\t\t.animate(animation, o.duration, o.options.easing, function() {\n\t\t\t\t\ttransfer.remove();\n\t\t\t\t\t(o.callback && o.callback.apply(elem[0], arguments));\n\t\t\t\t\telem.dequeue();\n\t\t\t\t});\n\t});\n};\n\n})(jQuery);\n"
  },
  {
    "path": "src/lib/jquery.layout-1.2.0.js",
    "content": "/*\r\n * jquery.layout 1.2.0\r\n *\r\n * Copyright (c) 2008 \r\n *   Fabrizio Balliano (http://www.fabrizioballiano.net)\r\n *   Kevin Dalman (http://allpro.net)\r\n *\r\n * Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html)\r\n * and MIT (http://www.opensource.org/licenses/mit-license.php) licenses.\r\n *\r\n * $Date: 2008-12-27 02:17:22 +0100 (sab, 27 dic 2008) $\r\n * $Rev: 203 $\r\n * \r\n * NOTE: For best code readability, view this with a fixed-space font and tabs equal to 4-chars\r\n */\r\n(function($) {\r\n\r\n$.fn.layout = function (opts) {\r\n\r\n/*\r\n * ###########################\r\n *   WIDGET CONFIG & OPTIONS\r\n * ###########################\r\n */\r\n\r\n\t// DEFAULTS for options\r\n\tvar \r\n\t\tprefix = \"ui-layout-\" // prefix for ALL selectors and classNames\r\n\t,\tdefaults = { //\tmisc default values\r\n\t\t\tpaneClass:\t\t\t\tprefix+\"pane\"\t\t// ui-layout-pane\r\n\t\t,\tresizerClass:\t\t\tprefix+\"resizer\"\t// ui-layout-resizer\r\n\t\t,\ttogglerClass:\t\t\tprefix+\"toggler\"\t// ui-layout-toggler\r\n\t\t,\ttogglerInnerClass:\t\tprefix+\"\"\t\t\t// ui-layout-open / ui-layout-closed\r\n\t\t,\tbuttonClass:\t\t\tprefix+\"button\"\t\t// ui-layout-button\r\n\t\t,\tcontentSelector:\t\t\".\"+prefix+\"content\"// ui-layout-content\r\n\t\t,\tcontentIgnoreSelector:\t\".\"+prefix+\"ignore\"\t// ui-layout-mask \r\n\t\t}\r\n\t;\r\n\r\n\t// DEFAULT PANEL OPTIONS - CHANGE IF DESIRED\r\n\tvar options = {\r\n\t\tname:\t\t\t\t\t\t\"\"\t\t\t// FUTURE REFERENCE - not used right now\r\n\t,\tscrollToBookmarkOnLoad:\t\ttrue\t\t// after creating a layout, scroll to bookmark in URL (.../page.htm#myBookmark)\r\n\t,\tdefaults: { // default options for 'all panes' - will be overridden by 'per-pane settings'\r\n\t\t\tapplyDefaultStyles: \tfalse\t\t// apply basic styles directly to resizers & buttons? If not, then stylesheet must handle it\r\n\t\t,\tclosable:\t\t\t\ttrue\t\t// pane can open & close\r\n\t\t,\tresizable:\t\t\t\ttrue\t\t// when open, pane can be resized \r\n\t\t,\tslidable:\t\t\t\ttrue\t\t// when closed, pane can 'slide' open over other panes - closes on mouse-out\r\n\t\t//,\tpaneSelector:\t\t\t[ ]\t\t\t// MUST be pane-specific!\r\n\t\t,\tcontentSelector:\t\tdefaults.contentSelector\t// INNER div/element to auto-size so only it scrolls, not the entire pane!\r\n\t\t,\tcontentIgnoreSelector:\tdefaults.contentIgnoreSelector\t// elem(s) to 'ignore' when measuring 'content'\r\n\t\t,\tpaneClass:\t\t\t\tdefaults.paneClass\t\t// border-Pane - default: 'ui-layout-pane'\r\n\t\t,\tresizerClass:\t\t\tdefaults.resizerClass\t// Resizer Bar\t\t- default: 'ui-layout-resizer'\r\n\t\t,\ttogglerClass:\t\t\tdefaults.togglerClass\t// Toggler Button\t- default: 'ui-layout-toggler'\r\n\t\t,\tbuttonClass:\t\t\tdefaults.buttonClass\t// CUSTOM Buttons\t- default: 'ui-layout-button-toggle/-open/-close/-pin'\r\n\t\t,\tresizerDragOpacity:\t\t1\t\t\t// option for ui.draggable\r\n\t\t//,\tresizerCursor:\t\t\t\"\"\t\t\t// MUST be pane-specific - cursor when over resizer-bar\r\n\t\t,\tmaskIframesOnResize:\ttrue\t\t// true = all iframes OR = iframe-selector(s) - adds masking-div during resizing/dragging\r\n\t\t//,\tsize:\t\t\t\t\t100\t\t\t// inital size of pane - defaults are set 'per pane'\r\n\t\t,\tminSize:\t\t\t\t0\t\t\t// when manually resizing a pane\r\n\t\t,\tmaxSize:\t\t\t\t0\t\t\t// ditto, 0 = no limit\r\n\t\t,\tspacing_open:\t\t\t6\t\t\t// space between pane and adjacent panes - when pane is 'open'\r\n\t\t,\tspacing_closed:\t\t\t6\t\t\t// ditto - when pane is 'closed'\r\n\t\t,\ttogglerLength_open:\t\t50\t\t\t// Length = WIDTH of toggler button on north/south edges - HEIGHT on east/west edges\r\n\t\t,\ttogglerLength_closed: \t50\t\t\t// 100% OR -1 means 'full height/width of resizer bar' - 0 means 'hidden'\r\n\t\t,\ttogglerAlign_open:\t\t\"center\"\t// top/left, bottom/right, center, OR...\r\n\t\t,\ttogglerAlign_closed:\t\"center\"\t// 1 => nn = offset from top/left, -1 => -nn == offset from bottom/right\r\n\t\t,\ttogglerTip_open:\t\t\"Close\"\t\t// Toggler tool-tip (title)\r\n\t\t,\ttogglerTip_closed:\t\t\"Open\"\t\t// ditto\r\n\t\t,\tresizerTip:\t\t\t\t\"Resize\"\t// Resizer tool-tip (title)\r\n\t\t,\tsliderTip:\t\t\t\t\"Slide Open\" // resizer-bar triggers 'sliding' when pane is closed\r\n\t\t,\tsliderCursor:\t\t\t\"pointer\"\t// cursor when resizer-bar will trigger 'sliding'\r\n\t\t,\tslideTrigger_open:\t\t\"click\"\t\t// click, dblclick, mouseover\r\n\t\t,\tslideTrigger_close:\t\t\"mouseout\"\t// click, mouseout\r\n\t\t,\thideTogglerOnSlide:\t\tfalse\t\t// when pane is slid-open, should the toggler show?\r\n\t\t,\ttogglerContent_open:\t\"\"\t\t\t// text or HTML to put INSIDE the toggler\r\n\t\t,\ttogglerContent_closed:\t\"\"\t\t\t// ditto\r\n\t\t,\tshowOverflowOnHover:\tfalse\t\t// will bind allowOverflow() utility to pane.onMouseOver\r\n\t\t,\tenableCursorHotkey:\t\ttrue\t\t// enabled 'cursor' hotkeys\r\n\t\t//,\tcustomHotkey:\t\t\t\"\"\t\t\t// MUST be pane-specific - EITHER a charCode OR a character\r\n\t\t,\tcustomHotkeyModifier:\t\"SHIFT\"\t\t// either 'SHIFT', 'CTRL' or 'CTRL+SHIFT' - NOT 'ALT'\r\n\t\t//\tNOTE: fxSss_open & fxSss_close options (eg: fxName_open) are auto-generated if not passed\r\n\t\t,\tfxName:\t\t\t\t\t\"slide\" \t// ('none' or blank), slide, drop, scale\r\n\t\t,\tfxSpeed:\t\t\t\tnull\t\t// slow, normal, fast, 200, nnn - if passed, will OVERRIDE fxSettings.duration\r\n\t\t,\tfxSettings:\t\t\t\t{}\t\t\t// can be passed, eg: { easing: \"easeOutBounce\", duration: 1500 }\r\n\t\t,\tinitClosed:\t\t\t\tfalse\t\t// true = init pane as 'closed'\r\n\t\t,\tinitHidden: \t\t\tfalse \t\t// true = init pane as 'hidden' - no resizer or spacing\r\n\t\t\r\n\t\t/*\tcallback options do not have to be set - listed here for reference only\r\n\t\t,\tonshow_start:\t\t\t\"\"\t\t\t// CALLBACK when pane STARTS to Show\t- BEFORE onopen/onhide_start\r\n\t\t,\tonshow_end:\t\t\t\t\"\"\t\t\t// CALLBACK when pane ENDS being Shown\t- AFTER  onopen/onhide_end\r\n\t\t,\tonhide_start:\t\t\t\"\"\t\t\t// CALLBACK when pane STARTS to Close\t- BEFORE onclose_start\r\n\t\t,\tonhide_end:\t\t\t\t\"\"\t\t\t// CALLBACK when pane ENDS being Closed\t- AFTER  onclose_end\r\n\t\t,\tonopen_start:\t\t\t\"\"\t\t\t// CALLBACK when pane STARTS to Open\r\n\t\t,\tonopen_end:\t\t\t\t\"\"\t\t\t// CALLBACK when pane ENDS being Opened\r\n\t\t,\tonclose_start:\t\t\t\"\"\t\t\t// CALLBACK when pane STARTS to Close\r\n\t\t,\tonclose_end:\t\t\t\"\"\t\t\t// CALLBACK when pane ENDS being Closed\r\n\t\t,\tonresize_start:\t\t\t\"\"\t\t\t// CALLBACK when pane STARTS to be ***MANUALLY*** Resized\r\n\t\t,\tonresize_end:\t\t\t\"\"\t\t\t// CALLBACK when pane ENDS being Resized ***FOR ANY REASON***\r\n\t\t*/\r\n\t\t}\r\n\t,\tnorth: {\r\n\t\t\tpaneSelector:\t\t\t\".\"+prefix+\"north\" // default = .ui-layout-north\r\n\t\t,\tsize:\t\t\t\t\t\"auto\"\r\n\t\t,\tresizerCursor:\t\t\t\"n-resize\"\r\n\t\t}\r\n\t,\tsouth: {\r\n\t\t\tpaneSelector:\t\t\t\".\"+prefix+\"south\" // default = .ui-layout-south\r\n\t\t,\tsize:\t\t\t\t\t\"auto\"\r\n\t\t,\tresizerCursor:\t\t\t\"s-resize\"\r\n\t\t}\r\n\t,\teast: {\r\n\t\t\tpaneSelector:\t\t\t\".\"+prefix+\"east\" // default = .ui-layout-east\r\n\t\t,\tsize:\t\t\t\t\t200\r\n\t\t,\tresizerCursor:\t\t\t\"e-resize\"\r\n\t\t}\r\n\t,\twest: {\r\n\t\t\tpaneSelector:\t\t\t\".\"+prefix+\"west\" // default = .ui-layout-west\r\n\t\t,\tsize:\t\t\t\t\t200\r\n\t\t,\tresizerCursor:\t\t\t\"w-resize\"\r\n\t\t}\r\n\t,\tcenter: {\r\n\t\t\tpaneSelector:\t\t\t\".\"+prefix+\"center\" // default = .ui-layout-center\r\n\t\t}\r\n\r\n\t};\r\n\r\n\r\n\tvar effects = { // LIST *PREDEFINED EFFECTS* HERE, even if effect has no settings\r\n\t\tslide:\t{\r\n\t\t\tall:\t{ duration:  \"fast\"\t} // eg: duration: 1000, easing: \"easeOutBounce\"\r\n\t\t,\tnorth:\t{ direction: \"up\"\t}\r\n\t\t,\tsouth:\t{ direction: \"down\"\t}\r\n\t\t,\teast:\t{ direction: \"right\"}\r\n\t\t,\twest:\t{ direction: \"left\"\t}\r\n\t\t}\r\n\t,\tdrop:\t{\r\n\t\t\tall:\t{ duration:  \"slow\"\t} // eg: duration: 1000, easing: \"easeOutQuint\"\r\n\t\t,\tnorth:\t{ direction: \"up\"\t}\r\n\t\t,\tsouth:\t{ direction: \"down\"\t}\r\n\t\t,\teast:\t{ direction: \"right\"}\r\n\t\t,\twest:\t{ direction: \"left\"\t}\r\n\t\t}\r\n\t,\tscale:\t{\r\n\t\t\tall:\t{ duration:  \"fast\"\t}\r\n\t\t}\r\n\t};\r\n\r\n\r\n\t// STATIC, INTERNAL CONFIG - DO NOT CHANGE THIS!\r\n\tvar config = {\r\n\t\tallPanes:\t\t\"north,south,east,west,center\"\r\n\t,\tborderPanes:\t\"north,south,east,west\"\r\n\t,\tzIndex: { // set z-index values here\r\n\t\t\tresizer_normal:\t1\t\t// normal z-index for resizer-bars\r\n\t\t,\tpane_normal:\t2\t\t// normal z-index for panes\r\n\t\t,\tmask:\t\t\t4\t\t// overlay div used to mask pane(s) during resizing\r\n\t\t,\tsliding:\t\t100\t\t// applied to both the pane and its resizer when a pane is 'slid open'\r\n\t\t,\tresizing:\t\t10000\t// applied to the CLONED resizer-bar when being 'dragged'\r\n\t\t,\tanimation:\t\t10000\t// applied to the pane when being animated - not applied to the resizer\r\n\t\t}\r\n\t,\tresizers: {\r\n\t\t\tcssReq: {\r\n\t\t\t\tposition: \t\"absolute\"\r\n\t\t\t,\tpadding: \t0\r\n\t\t\t,\tmargin: \t0\r\n\t\t\t,\tfontSize:\t\"1px\"\r\n\t\t\t,\ttextAlign:\t\"left\" // to counter-act \"center\" alignment!\r\n\t\t\t,\toverflow: \t\"hidden\" // keep toggler button from overflowing\r\n\t\t\t,\tzIndex: \t1\r\n\t\t\t}\r\n\t\t,\tcssDef: { // DEFAULT CSS - applied if: options.PANE.applyDefaultStyles=true\r\n\t\t\t\tbackground: \"#DDD\"\r\n\t\t\t,\tborder:\t\t\"none\"\r\n\t\t\t}\r\n\t\t}\r\n\t,\ttogglers: {\r\n\t\t\tcssReq: {\r\n\t\t\t\tposition: \t\"absolute\"\r\n\t\t\t,\tdisplay: \t\"block\"\r\n\t\t\t,\tpadding: \t0\r\n\t\t\t,\tmargin: \t0\r\n\t\t\t,\toverflow:\t\"hidden\"\r\n\t\t\t,\ttextAlign:\t\"center\"\r\n\t\t\t,\tfontSize:\t\"1px\"\r\n\t\t\t,\tcursor: \t\"pointer\"\r\n\t\t\t,\tzIndex: \t1\r\n\t\t\t}\r\n\t\t,\tcssDef: { // DEFAULT CSS - applied if: options.PANE.applyDefaultStyles=true\r\n\t\t\t\tbackground: \"#AAA\"\r\n\t\t\t}\r\n\t\t}\r\n\t,\tcontent: {\r\n\t\t\tcssReq: {\r\n\t\t\t\toverflow:\t\"auto\"\r\n\t\t\t}\r\n\t\t,\tcssDef: {}\r\n\t\t}\r\n\t,\tdefaults: { // defaults for ALL panes - overridden by 'per-pane settings' below\r\n\t\t\tcssReq: {\r\n\t\t\t\tposition: \t\"absolute\"\r\n\t\t\t,\tmargin:\t\t0\r\n\t\t\t,\tzIndex: \t2\r\n\t\t\t}\r\n\t\t,\tcssDef: {\r\n\t\t\t\tpadding:\t\"10px\"\r\n\t\t\t,\tbackground:\t\"#FFF\"\r\n\t\t\t,\tborder:\t\t\"1px solid #BBB\"\r\n\t\t\t,\toverflow:\t\"auto\"\r\n\t\t\t}\r\n\t\t}\r\n\t,\tnorth: {\r\n\t\t\tedge:\t\t\t\"top\"\r\n\t\t,\tsizeType:\t\t\"height\"\r\n\t\t,\tdir:\t\t\t\"horz\"\r\n\t\t,\tcssReq: {\r\n\t\t\t\ttop: \t\t0\r\n\t\t\t,\tbottom: \t\"auto\"\r\n\t\t\t,\tleft: \t\t0\r\n\t\t\t,\tright: \t\t0\r\n\t\t\t,\twidth: \t\t\"auto\"\r\n\t\t\t//\theight: \tDYNAMIC\r\n\t\t\t}\r\n\t\t}\r\n\t,\tsouth: {\r\n\t\t\tedge:\t\t\t\"bottom\"\r\n\t\t,\tsizeType:\t\t\"height\"\r\n\t\t,\tdir:\t\t\t\"horz\"\r\n\t\t,\tcssReq: {\r\n\t\t\t\ttop: \t\t\"auto\"\r\n\t\t\t,\tbottom: \t0\r\n\t\t\t,\tleft: \t\t0\r\n\t\t\t,\tright: \t\t0\r\n\t\t\t,\twidth: \t\t\"auto\"\r\n\t\t\t//\theight: \tDYNAMIC\r\n\t\t\t}\r\n\t\t}\r\n\t,\teast: {\r\n\t\t\tedge:\t\t\t\"right\"\r\n\t\t,\tsizeType:\t\t\"width\"\r\n\t\t,\tdir:\t\t\t\"vert\"\r\n\t\t,\tcssReq: {\r\n\t\t\t\tleft: \t\t\"auto\"\r\n\t\t\t,\tright: \t\t0\r\n\t\t\t,\ttop: \t\t\"auto\" // DYNAMIC\r\n\t\t\t,\tbottom: \t\"auto\" // DYNAMIC\r\n\t\t\t,\theight: \t\"auto\"\r\n\t\t\t//\twidth: \t\tDYNAMIC\r\n\t\t\t}\r\n\t\t}\r\n\t,\twest: {\r\n\t\t\tedge:\t\t\t\"left\"\r\n\t\t,\tsizeType:\t\t\"width\"\r\n\t\t,\tdir:\t\t\t\"vert\"\r\n\t\t,\tcssReq: {\r\n\t\t\t\tleft: \t\t0\r\n\t\t\t,\tright: \t\t\"auto\"\r\n\t\t\t,\ttop: \t\t\"auto\" // DYNAMIC\r\n\t\t\t,\tbottom: \t\"auto\" // DYNAMIC\r\n\t\t\t,\theight: \t\"auto\"\r\n\t\t\t//\twidth: \t\tDYNAMIC\r\n\t\t\t}\r\n\t\t}\r\n\t,\tcenter: {\r\n\t\t\tdir:\t\t\t\"center\"\r\n\t\t,\tcssReq: {\r\n\t\t\t\tleft: \t\t\"auto\" // DYNAMIC\r\n\t\t\t,\tright: \t\t\"auto\" // DYNAMIC\r\n\t\t\t,\ttop: \t\t\"auto\" // DYNAMIC\r\n\t\t\t,\tbottom: \t\"auto\" // DYNAMIC\r\n\t\t\t,\theight: \t\"auto\"\r\n\t\t\t,\twidth: \t\t\"auto\"\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\r\n\r\n\t// DYNAMIC DATA\r\n\tvar state = {\r\n\t\t// generate random 'ID#' to identify layout - used to create global namespace for timers\r\n\t\tid:\t\t\tMath.floor(Math.random() * 10000)\r\n\t,\tcontainer:\t{}\r\n\t,\tnorth:\t\t{}\r\n\t,\tsouth:\t\t{}\r\n\t,\teast:\t\t{}\r\n\t,\twest:\t\t{}\r\n\t,\tcenter:\t\t{}\r\n\t};\r\n\r\n\r\n\tvar \r\n\t\taltEdge = {\r\n\t\t\ttop:\t\"bottom\"\r\n\t\t,\tbottom: \"top\"\r\n\t\t,\tleft:\t\"right\"\r\n\t\t,\tright:\t\"left\"\r\n\t\t}\r\n\t,\taltSide = {\r\n\t\t\tnorth:\t\"south\"\r\n\t\t,\tsouth:\t\"north\"\r\n\t\t,\teast: \t\"west\"\r\n\t\t,\twest: \t\"east\"\r\n\t\t}\r\n\t;\r\n\r\n\r\n/*\r\n * ###########################\r\n *  INTERNAL HELPER FUNCTIONS\r\n * ###########################\r\n */\r\n\r\n\t/**\r\n\t * isStr\r\n\t *\r\n\t * Returns true if passed param is EITHER a simple string OR a 'string object' - otherwise returns false\r\n\t */\r\n\tvar isStr = function (o) {\r\n\t\tif (typeof o == \"string\")\r\n\t\t\treturn true;\r\n\t\telse if (typeof o == \"object\") {\r\n\t\t\ttry {\r\n\t\t\t\tvar match = o.constructor.toString().match(/string/i); \r\n\t\t\t\treturn (match !== null);\r\n\t\t\t} catch (e) {} \r\n\t\t}\r\n\t\treturn false;\r\n\t};\r\n\r\n\t/**\r\n\t * str\r\n\t *\r\n\t * Returns a simple string if the passed param is EITHER a simple string OR a 'string object',\r\n\t *  else returns the original object\r\n\t */\r\n\tvar str = function (o) {\r\n\t\tif (typeof o == \"string\" || isStr(o)) return $.trim(o); // trim converts 'String object' to a simple string\r\n\t\telse return o;\r\n\t};\r\n\r\n\t/**\r\n\t * min / max\r\n\t *\r\n\t * Alias for Math.min/.max to simplify coding\r\n\t */\r\n\tvar min = function (x,y) { return Math.min(x,y); };\r\n\tvar max = function (x,y) { return Math.max(x,y); };\r\n\r\n\t/**\r\n\t * transformData\r\n\t *\r\n\t * Processes the options passed in and transforms them into the format used by layout()\r\n\t * Missing keys are added, and converts the data if passed in 'flat-format' (no sub-keys)\r\n\t * In flat-format, pane-specific-settings are prefixed like: north__optName  (2-underscores)\r\n\t * To update effects, options MUST use nested-keys format, with an effects key\r\n\t *\r\n\t * @callers  initOptions()\r\n\t * @params  JSON  d  Data/options passed by user - may be a single level or nested levels\r\n\t * @returns JSON  Creates a data struture that perfectly matches 'options', ready to be imported\r\n\t */\r\n\tvar transformData = function (d) {\r\n\t\tvar json = { defaults:{fxSettings:{}}, north:{fxSettings:{}}, south:{fxSettings:{}}, east:{fxSettings:{}}, west:{fxSettings:{}}, center:{fxSettings:{}} };\r\n\t\td = d || {};\r\n\t\tif (d.effects || d.defaults || d.north || d.south || d.west || d.east || d.center)\r\n\t\t\tjson = $.extend( json, d ); // already in json format - add to base keys\r\n\t\telse\r\n\t\t\t// convert 'flat' to 'nest-keys' format - also handles 'empty' user-options\r\n\t\t\t$.each( d, function (key,val) {\r\n\t\t\t\ta = key.split(\"__\");\r\n\t\t\t\tjson[ a[1] ? a[0] : \"defaults\" ][ a[1] ? a[1] : a[0] ] = val;\r\n\t\t\t});\r\n\t\treturn json;\r\n\t};\r\n\r\n\t/**\r\n\t * setFlowCallback\r\n\t *\r\n\t * Set an INTERNAL callback to avoid simultaneous animation\r\n\t * Runs only if needed and only if all callbacks are not 'already set'!\r\n\t *\r\n\t * @param String   action  Either 'open' or 'close'\r\n\t * @pane  String   pane    A valid border-pane name, eg 'west'\r\n\t * @pane  Boolean  param   Extra param for callback (optional)\r\n\t */\r\n\tvar setFlowCallback = function (action, pane, param) {\r\n\t\tvar\r\n\t\t\tcb = action +\",\"+ pane +\",\"+ (param ? 1 : 0)\r\n\t\t,\tcP, cbPane\r\n\t\t;\r\n\t\t$.each(c.borderPanes.split(\",\"), function (i,p) {\r\n\t\t\tif (c[p].isMoving) {\r\n\t\t\t\tbindCallback(p); // TRY to bind a callback\r\n\t\t\t\treturn false; // BREAK\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tfunction bindCallback (p, test) {\r\n\t\t\tcP = c[p];\r\n\t\t\tif (!cP.doCallback) {\r\n\t\t\t\tcP.doCallback = true;\r\n\t\t\t\tcP.callback = cb;\r\n\t\t\t}\r\n\t\t\telse { // try to 'chain' this callback\r\n\t\t\t\tcpPane = cP.callback.split(\",\")[1]; // 2nd param is 'pane'\r\n\t\t\t\tif (cpPane != p && cpPane != pane) // callback target NOT 'itself' and NOT 'this pane'\r\n\t\t\t\t\tbindCallback (cpPane, true); // RECURSE\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\r\n\t/**\r\n\t * execFlowCallback\r\n\t *\r\n\t * RUN the INTERNAL callback for this pane - if one exists\r\n\t *\r\n\t * @param String   action  Either 'open' or 'close'\r\n\t * @pane  String   pane    A valid border-pane name, eg 'west'\r\n\t * @pane  Boolean  param   Extra param for callback (optional)\r\n\t */\r\n\tvar execFlowCallback = function (pane) {\r\n\t\tvar cP = c[pane];\r\n\r\n\t\t// RESET flow-control flaGs\r\n\t\tc.isLayoutBusy = false;\r\n\t\tdelete cP.isMoving;\r\n\t\tif (!cP.doCallback || !cP.callback) return;\r\n\r\n\t\tcP.doCallback = false; // RESET logic flag\r\n\r\n\t\t// EXECUTE the callback\r\n\t\tvar\r\n\t\t\tcb = cP.callback.split(\",\")\r\n\t\t,\tparam = (cb[2] > 0 ? true : false)\r\n\t\t;\r\n\t\tif (cb[0] == \"open\")\r\n\t\t\topen( cb[1], param  );\r\n\t\telse if (cb[0] == \"close\")\r\n\t\t\tclose( cb[1], param );\r\n\r\n\t\tif (!cP.doCallback) cP.callback = null; // RESET - unless callback above enabled it again!\r\n\t};\r\n\r\n\t/**\r\n\t * execUserCallback\r\n\t *\r\n\t * Executes a Callback function after a trigger event, like resize, open or close\r\n\t *\r\n\t * @param String  pane   This is passed only so we can pass the 'pane object' to the callback\r\n\t * @param String  v_fn  Accepts a function name, OR a comma-delimited array: [0]=function name, [1]=argument\r\n\t */\r\n\tvar execUserCallback = function (pane, v_fn) {\r\n\t\tif (!v_fn) return;\r\n\t\tvar fn;\r\n\t\ttry {\r\n\t\t\tif (typeof v_fn == \"function\")\r\n\t\t\t\tfn = v_fn;\t\r\n\t\t\telse if (typeof v_fn != \"string\")\r\n\t\t\t\treturn;\r\n\t\t\telse if (v_fn.indexOf(\",\") > 0) {\r\n\t\t\t\t// function name cannot contain a comma, so must be a function name AND a 'name' parameter\r\n\t\t\t\tvar\r\n\t\t\t\t\targs = v_fn.split(\",\")\r\n\t\t\t\t,\tfn = eval(args[0])\r\n\t\t\t\t;\r\n\t\t\t\tif (typeof fn==\"function\" && args.length > 1)\r\n\t\t\t\t\treturn fn(args[1]); // pass the argument parsed from 'list'\r\n\t\t\t}\r\n\t\t\telse // just the name of an external function?\r\n\t\t\t\tfn = eval(v_fn);\r\n\r\n\t\t\tif (typeof fn==\"function\")\r\n\t\t\t\t// pass data: pane-name, pane-element, pane-state, pane-options, and layout-name\r\n\t\t\t\treturn fn( pane, $Ps[pane], $.extend({},state[pane]), $.extend({},options[pane]), options.name );\r\n\t\t}\r\n\t\tcatch (ex) {}\r\n\t};\r\n\r\n\t/**\r\n\t * cssNum\r\n\t *\r\n\t * Returns the 'current CSS value' for an element - returns 0 if property does not exist\r\n\t *\r\n\t * @callers  Called by many methods\r\n\t * @param jQuery  $Elem  Must pass a jQuery object - first element is processed\r\n\t * @param String  property  The name of the CSS property, eg: top, width, etc.\r\n\t * @returns Variant  Usually is used to get an integer value for position (top, left) or size (height, width)\r\n\t */\r\n\tvar cssNum = function ($E, prop) {\r\n\t\tvar\r\n\t\t\tval = 0\r\n\t\t,\thidden = false\r\n\t\t,\tvisibility = \"\"\r\n\t\t;\r\n\t\tif (!$.browser.msie) { // IE CAN read dimensions of 'hidden' elements - FF CANNOT\r\n\t\t\tif ($.curCSS($E[0], \"display\", true) == \"none\") {\r\n\t\t\t\thidden = true;\r\n\t\t\t\tvisibility = $.curCSS($E[0], \"visibility\", true); // SAVE current setting\r\n\t\t\t\t$E.css({ display: \"block\", visibility: \"hidden\" }); // show element 'invisibly' so we can measure it\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tval = parseInt($.curCSS($E[0], prop, true), 10) || 0;\r\n\r\n\t\tif (hidden) { // WAS hidden, so put back the way it was\r\n\t\t\t$E.css({ display: \"none\" });\r\n\t\t\tif (visibility && visibility != \"hidden\")\r\n\t\t\t\t$E.css({ visibility: visibility }); // reset 'visibility'\r\n\t\t}\r\n\r\n\t\treturn val;\r\n\t};\r\n\r\n\t/**\r\n\t * cssW / cssH / cssSize\r\n\t *\r\n\t * Contains logic to check boxModel & browser, and return the correct width/height for the current browser/doctype\r\n\t *\r\n\t * @callers  initPanes(), sizeMidPanes(), initHandles(), sizeHandles()\r\n\t * @param Variant  elem  Can accept a 'pane' (east, west, etc) OR a DOM object OR a jQuery object\r\n\t * @param Integer  outerWidth/outerHeight  (optional) Can pass a width, allowing calculations BEFORE element is resized\r\n\t * @returns Integer  Returns the innerHeight of the elem by subtracting padding and borders\r\n\t *\r\n\t * @TODO  May need to add additional logic to handle more browser/doctype variations?\r\n\t */\r\n\tvar cssW = function (e, outerWidth) {\r\n\t\tvar $E;\r\n\t\tif (isStr(e)) {\r\n\t\t\te = str(e);\r\n\t\t\t$E = $Ps[e];\r\n\t\t}\r\n\t\telse\r\n\t\t\t$E = $(e);\r\n\r\n\t\t// a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed\r\n\t\tif (outerWidth <= 0)\r\n\t\t\treturn 0;\r\n\t\telse if (!(outerWidth>0))\r\n\t\t\touterWidth = isStr(e) ? getPaneSize(e) : $E.outerWidth();\r\n\r\n\t\tif (!$.boxModel)\r\n\t\t\treturn outerWidth;\r\n\r\n\t\telse // strip border and padding size from outerWidth to get CSS Width\r\n\t\t\treturn outerWidth\r\n\t\t\t\t- cssNum($E, \"paddingLeft\")\t\t\r\n\t\t\t\t- cssNum($E, \"paddingRight\")\r\n\t\t\t\t- ($.curCSS($E[0], \"borderLeftStyle\", true) == \"none\" ? 0 : cssNum($E, \"borderLeftWidth\"))\r\n\t\t\t\t- ($.curCSS($E[0], \"borderRightStyle\", true) == \"none\" ? 0 : cssNum($E, \"borderRightWidth\"))\r\n\t\t\t;\r\n\t};\r\n\tvar cssH = function (e, outerHeight) {\r\n\t\tvar $E;\r\n\t\tif (isStr(e)) {\r\n\t\t\te = str(e);\r\n\t\t\t$E = $Ps[e];\r\n\t\t}\r\n\t\telse\r\n\t\t\t$E = $(e);\r\n\r\n\t\t// a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed\r\n\t\tif (outerHeight <= 0)\r\n\t\t\treturn 0;\r\n\t\telse if (!(outerHeight>0))\r\n\t\t\touterHeight = (isStr(e)) ? getPaneSize(e) : $E.outerHeight();\r\n\r\n\t\tif (!$.boxModel)\r\n\t\t\treturn outerHeight;\r\n\r\n\t\telse // strip border and padding size from outerHeight to get CSS Height\r\n\t\t\treturn outerHeight\r\n\t\t\t\t- cssNum($E, \"paddingTop\")\r\n\t\t\t\t- cssNum($E, \"paddingBottom\")\r\n\t\t\t\t- ($.curCSS($E[0], \"borderTopStyle\", true) == \"none\" ? 0 : cssNum($E, \"borderTopWidth\"))\r\n\t\t\t\t- ($.curCSS($E[0], \"borderBottomStyle\", true) == \"none\" ? 0 : cssNum($E, \"borderBottomWidth\"))\r\n\t\t\t;\r\n\t};\r\n\tvar cssSize = function (pane, outerSize) {\r\n\t\tif (c[pane].dir==\"horz\") // pane = north or south\r\n\t\t\treturn cssH(pane, outerSize);\r\n\t\telse // pane = east or west\r\n\t\t\treturn cssW(pane, outerSize);\r\n\t};\r\n\r\n\t/**\r\n\t * getPaneSize\r\n\t *\r\n\t * Calculates the current 'size' (width or height) of a border-pane - optionally with 'pane spacing' added\r\n\t *\r\n\t * @returns Integer  Returns EITHER Width for east/west panes OR Height for north/south panes - adjusted for boxModel & browser\r\n\t */\r\n\tvar getPaneSize = function (pane, inclSpace) {\r\n\t\tvar \r\n\t\t\t$P\t= $Ps[pane]\r\n\t\t,\to\t= options[pane]\r\n\t\t,\ts\t= state[pane]\r\n\t\t,\toSp\t= (inclSpace ? o.spacing_open : 0)\r\n\t\t,\tcSp\t= (inclSpace ? o.spacing_closed : 0)\r\n\t\t;\r\n\t\tif (!$P || s.isHidden)\r\n\t\t\treturn 0;\r\n\t\telse if (s.isClosed || (s.isSliding && inclSpace))\r\n\t\t\treturn cSp;\r\n\t\telse if (c[pane].dir == \"horz\")\r\n\t\t\treturn $P.outerHeight() + oSp;\r\n\t\telse // dir == \"vert\"\r\n\t\t\treturn $P.outerWidth() + oSp;\r\n\t};\r\n\r\n\tvar setPaneMinMaxSizes = function (pane) {\r\n\t\tvar \r\n\t\t\td\t\t\t\t= cDims\r\n\t\t,\tedge\t\t\t= c[pane].edge\r\n\t\t,\tdir\t\t\t\t= c[pane].dir\r\n\t\t,\to\t\t\t\t= options[pane]\r\n\t\t,\ts\t\t\t\t= state[pane]\r\n\t\t,\t$P\t\t\t\t= $Ps[pane]\r\n\t\t,\t$altPane\t\t= $Ps[ altSide[pane] ]\r\n\t\t,\tpaneSpacing\t\t= o.spacing_open\r\n\t\t,\taltPaneSpacing\t= options[ altSide[pane] ].spacing_open\r\n\t\t,\taltPaneSize\t\t= (!$altPane ? 0 : (dir==\"horz\" ? $altPane.outerHeight() : $altPane.outerWidth()))\r\n\t\t,\tcontainerSize\t= (dir==\"horz\" ? d.innerHeight : d.innerWidth)\r\n\t\t//\tlimitSize prevents this pane from 'overlapping' opposite pane - even if opposite pane is currently closed\r\n\t\t,\tlimitSize\t\t= containerSize - paneSpacing - altPaneSize - altPaneSpacing\r\n\t\t,\tminSize\t\t\t= s.minSize || 0\r\n\t\t,\tmaxSize\t\t\t= Math.min(s.maxSize || 9999, limitSize)\r\n\t\t,\tminPos, maxPos\t// used to set resizing limits\r\n\t\t;\r\n\t\tswitch (pane) {\r\n\t\t\tcase \"north\":\tminPos = d.offsetTop + minSize;\r\n\t\t\t\t\t\t\tmaxPos = d.offsetTop + maxSize;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\tcase \"west\":\tminPos = d.offsetLeft + minSize;\r\n\t\t\t\t\t\t\tmaxPos = d.offsetLeft + maxSize;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\tcase \"south\":\tminPos = d.offsetTop + d.innerHeight - maxSize;\r\n\t\t\t\t\t\t\tmaxPos = d.offsetTop + d.innerHeight - minSize;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\tcase \"east\":\tminPos = d.offsetLeft + d.innerWidth - maxSize;\r\n\t\t\t\t\t\t\tmaxPos = d.offsetLeft + d.innerWidth - minSize;\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t}\r\n\t\t// save data to pane-state\r\n\t\t$.extend(s, { minSize: minSize, maxSize: maxSize, minPosition: minPos, maxPosition: maxPos });\r\n\t};\r\n\r\n\t/**\r\n\t * getPaneDims\r\n\t *\r\n\t * Returns data for setting the size/position of center pane. Date is also used to set Height for east/west panes\r\n\t *\r\n\t * @returns JSON  Returns a hash of all dimensions: top, bottom, left, right, (outer) width and (outer) height\r\n\t */\r\n\tvar getPaneDims = function () {\r\n\t\tvar d = {\r\n\t\t\ttop:\tgetPaneSize(\"north\", true) // true = include 'spacing' value for p\r\n\t\t,\tbottom:\tgetPaneSize(\"south\", true)\r\n\t\t,\tleft:\tgetPaneSize(\"west\", true)\r\n\t\t,\tright:\tgetPaneSize(\"east\", true)\r\n\t\t,\twidth:\t0\r\n\t\t,\theight:\t0\r\n\t\t};\r\n\r\n\t\twith (d) {\r\n\t\t\twidth \t= cDims.innerWidth - left - right;\r\n\t\t\theight \t= cDims.innerHeight - bottom - top;\r\n\t\t\t// now add the 'container border/padding' to get final positions - relative to the container\r\n\t\t\ttop\t\t+= cDims.top;\r\n\t\t\tbottom\t+= cDims.bottom;\r\n\t\t\tleft\t+= cDims.left;\r\n\t\t\tright\t+= cDims.right;\r\n\t\t}\r\n\r\n\t\treturn d;\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * getElemDims\r\n\t *\r\n\t * Returns data for setting size of an element (container or a pane).\r\n\t *\r\n\t * @callers  create(), onWindowResize() for container, plus others for pane\r\n\t * @returns JSON  Returns a hash of all dimensions: top, bottom, left, right, outerWidth, innerHeight, etc\r\n\t */\r\n\tvar getElemDims = function ($E) {\r\n\t\tvar\r\n\t\t\td = {} // dimensions hash\r\n\t\t,\te, b, p // edge, border, padding\r\n\t\t;\r\n\r\n\t\t$.each(\"Left,Right,Top,Bottom\".split(\",\"), function () {\r\n\t\t\te = str(this);\r\n\t\t\tb = d[\"border\" +e] = cssNum($E, \"border\"+e+\"Width\");\r\n\t\t\tp = d[\"padding\"+e] = cssNum($E, \"padding\"+e);\r\n\t\t\td[\"offset\" +e] = b + p; // total offset of content from outer edge\r\n\t\t\t// if BOX MODEL, then 'position' = PADDING (ignore borderWidth)\r\n\t\t\tif ($E == $Container)\r\n\t\t\t\td[e.toLowerCase()] = ($.boxModel ? p : 0); \r\n\t\t});\r\n\r\n\t\td.innerWidth  = d.outerWidth  = $E.outerWidth();\r\n\t\td.innerHeight = d.outerHeight = $E.outerHeight();\r\n\t\tif ($.boxModel) {\r\n\t\t\td.innerWidth  -= (d.offsetLeft + d.offsetRight);\r\n\t\t\td.innerHeight -= (d.offsetTop  + d.offsetBottom);\r\n\t\t}\r\n\r\n\t\treturn d;\r\n\t};\r\n\r\n\r\n\tvar setTimer = function (pane, action, fn, ms) {\r\n\t\tvar\r\n\t\t\tLayout = window.layout = window.layout || {}\r\n\t\t,\tTimers = Layout.timers = Layout.timers || {}\r\n\t\t,\tname = \"layout_\"+ state.id +\"_\"+ pane +\"_\"+ action // UNIQUE NAME for every layout-pane-action\r\n\t\t;\r\n\t\tif (Timers[name]) return; // timer already set!\r\n\t\telse Timers[name] = setTimeout(fn, ms);\r\n\t};\r\n\r\n\tvar clearTimer = function (pane, action) {\r\n\t\tvar\r\n\t\t\tLayout = window.layout = window.layout || {}\r\n\t\t,\tTimers = Layout.timers = Layout.timers || {}\r\n\t\t,\tname = \"layout_\"+ state.id +\"_\"+ pane +\"_\"+ action // UNIQUE NAME for every layout-pane-action\r\n\t\t;\r\n\t\tif (Timers[name]) {\r\n\t\t\tclearTimeout( Timers[name] );\r\n\t\t\tdelete Timers[name];\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\telse\r\n\t\t\treturn false;\r\n\t};\r\n\r\n\r\n/*\r\n * ###########################\r\n *   INITIALIZATION METHODS\r\n * ###########################\r\n */\r\n\r\n\t/**\r\n\t * create\r\n\t *\r\n\t * Initialize the layout - called automatically whenever an instance of layout is created\r\n\t *\r\n\t * @callers  NEVER explicity called\r\n\t * @returns  An object pointer to the instance created\r\n\t */\r\n\tvar create = function () {\r\n\t\t// initialize config/options\r\n\t\tinitOptions();\r\n\r\n\t\t// initialize all objects\r\n\t\tinitContainer();\t// set CSS as needed and init state.container dimensions\r\n\t\tinitPanes();\t\t// size & position all panes\r\n\t\tinitHandles();\t\t// create and position all resize bars & togglers buttons\r\n\t\tinitResizable();\t// activate resizing on all panes where resizable=true\r\n\t\tsizeContent(\"all\");\t// AFTER panes & handles have been initialized, size 'content' divs\r\n\r\n\t\tif (options.scrollToBookmarkOnLoad)\r\n\t\t\twith (self.location) if (hash) replace( hash ); // scrollTo Bookmark\r\n\r\n\t\t// bind hotkey function - keyDown - if required\r\n\t\tinitHotkeys();\r\n\r\n\t\t// bind resizeAll() for 'this layout instance' to window.resize event\r\n\t\t$(window).resize(function () {\r\n\t\t\tvar timerID = \"timerLayout_\"+state.id;\r\n\t\t\tif (window[timerID]) clearTimeout(window[timerID]);\r\n\t\t\twindow[timerID] = null;\r\n\t\t\tif (true || $.browser.msie) // use a delay for IE because the resize event fires repeatly\r\n\t\t\t\twindow[timerID] = setTimeout(resizeAll, 100);\r\n\t\t\telse // most other browsers have a built-in delay before firing the resize event\r\n\t\t\t\tresizeAll(); // resize all layout elements NOW!\r\n\t\t});\r\n\t};\r\n\r\n\t/**\r\n\t * initContainer\r\n\t *\r\n\t * Validate and initialize container CSS and events\r\n\t *\r\n\t * @callers  create()\r\n\t */\r\n\tvar initContainer = function () {\r\n\t\ttry { // format html/body if this is a full page layout\r\n\t\t\tif ($Container[0].tagName == \"BODY\") {\r\n\t\t\t\t$(\"html\").css({\r\n\t\t\t\t\theight:\t\t\"100%\"\r\n\t\t\t\t,\toverflow:\t\"hidden\"\r\n\t\t\t\t});\r\n\t\t\t\t$(\"body\").css({\r\n\t\t\t\t\tposition:\t\"relative\"\r\n\t\t\t\t,\theight:\t\t\"100%\"\r\n\t\t\t\t,\toverflow:\t\"hidden\"\r\n\t\t\t\t,\tmargin:\t\t0\r\n\t\t\t\t,\tpadding:\t0\t\t// TODO: test whether body-padding could be handled?\r\n\t\t\t\t,\tborder:\t\t\"none\"\t// a body-border creates problems because it cannot be measured!\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t\telse { // set required CSS - overflow and position\r\n\t\t\t\tvar\r\n\t\t\t\t\tCSS\t= { overflow: \"hidden\" } // make sure container will not 'scroll'\r\n\t\t\t\t,\tp\t= $Container.css(\"position\")\r\n\t\t\t\t,\th\t= $Container.css(\"height\")\r\n\t\t\t\t;\r\n\t\t\t\t// if this is a NESTED layout, then outer-pane ALREADY has position and height\r\n\t\t\t\tif (!$Container.hasClass(\"ui-layout-pane\")) {\r\n\t\t\t\t\tif (!p || \"fixed,absolute,relative\".indexOf(p) < 0)\r\n\t\t\t\t\t\tCSS.position = \"relative\"; // container MUST have a 'position'\r\n\t\t\t\t\tif (!h || h==\"auto\")\r\n\t\t\t\t\t\tCSS.height = \"100%\"; // container MUST have a 'height'\r\n\t\t\t\t}\r\n\t\t\t\t$Container.css( CSS );\r\n\t\t\t}\r\n\t\t} catch (ex) {}\r\n\r\n\t\t// get layout-container dimensions (updated when necessary)\r\n\t\tcDims = state.container = getElemDims( $Container ); // update data-pointer too\r\n\t};\r\n\r\n\t/**\r\n\t * initHotkeys\r\n\t *\r\n\t * Bind layout hotkeys - if options enabled\r\n\t *\r\n\t * @callers  create()\r\n\t */\r\n\tvar initHotkeys = function () {\r\n\t\t// bind keyDown to capture hotkeys, if option enabled for ANY pane\r\n\t\t$.each(c.borderPanes.split(\",\"), function (i,pane) {\r\n\t\t\tvar o = options[pane];\r\n\t\t\tif (o.enableCursorHotkey || o.customHotkey) {\r\n\t\t\t\t$(document).keydown( keyDown ); // only need to bind this ONCE\r\n\t\t\t\treturn false; // BREAK - binding was done\r\n\t\t\t}\r\n\t\t});\r\n\t};\r\n\r\n\t/**\r\n\t * initOptions\r\n\t *\r\n\t * Build final CONFIG and OPTIONS data\r\n\t *\r\n\t * @callers  create()\r\n\t */\r\n\tvar initOptions = function () {\r\n\t\t// simplify logic by making sure passed 'opts' var has basic keys\r\n\t\topts = transformData( opts );\r\n\r\n\t\t// update default effects, if case user passed key\r\n\t\tif (opts.effects) {\r\n\t\t\t$.extend( effects, opts.effects );\r\n\t\t\tdelete opts.effects;\r\n\t\t}\r\n\r\n\t\t// see if any 'global options' were specified\r\n\t\t$.each(\"name,scrollToBookmarkOnLoad\".split(\",\"), function (idx,key) {\r\n\t\t\tif (opts[key] !== undefined)\r\n\t\t\t\toptions[key] = opts[key];\r\n\t\t\telse if (opts.defaults[key] !== undefined) {\r\n\t\t\t\toptions[key] = opts.defaults[key];\r\n\t\t\t\tdelete opts.defaults[key];\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// remove any 'defaults' that MUST be set 'per-pane'\r\n\t\t$.each(\"paneSelector,resizerCursor,customHotkey\".split(\",\"),\r\n\t\t\tfunction (idx,key) { delete opts.defaults[key]; } // is OK if key does not exist\r\n\t\t);\r\n\r\n\t\t// now update options.defaults\r\n\t\t$.extend( options.defaults, opts.defaults );\r\n\t\t// make sure required sub-keys exist\r\n\t\t//if (typeof options.defaults.fxSettings != \"object\") options.defaults.fxSettings = {};\r\n\r\n\t\t// merge all config & options for the 'center' pane\r\n\t\tc.center = $.extend( true, {}, c.defaults, c.center );\r\n\t\t$.extend( options.center, opts.center );\r\n\t\t// Most 'default options' do not apply to 'center', so add only those that DO\r\n\t\tvar o_Center = $.extend( true, {}, options.defaults, opts.defaults, options.center ); // TEMP data\r\n\t\t$.each(\"paneClass,contentSelector,contentIgnoreSelector,applyDefaultStyles,showOverflowOnHover\".split(\",\"),\r\n\t\t\tfunction (idx,key) { options.center[key] = o_Center[key]; }\r\n\t\t);\r\n\r\n\t\tvar defs = options.defaults;\r\n\r\n\t\t// create a COMPLETE set of options for EACH border-pane\r\n\t\t$.each(c.borderPanes.split(\",\"), function(i,pane) {\r\n\t\t\t// apply 'pane-defaults' to CONFIG.PANE\r\n\t\t\tc[pane] = $.extend( true, {}, c.defaults, c[pane] );\r\n\t\t\t// apply 'pane-defaults' +  user-options to OPTIONS.PANE\r\n\t\t\to = options[pane] = $.extend( true, {}, options.defaults, options[pane], opts.defaults, opts[pane] );\r\n\r\n\t\t\t// make sure we have base-classes\r\n\t\t\tif (!o.paneClass)\t\to.paneClass\t\t= defaults.paneClass;\r\n\t\t\tif (!o.resizerClass)\to.resizerClass\t= defaults.resizerClass;\r\n\t\t\tif (!o.togglerClass)\to.togglerClass\t= defaults.togglerClass;\r\n\r\n\t\t\t// create FINAL fx options for each pane, ie: options.PANE.fxName/fxSpeed/fxSettings[_open|_close]\r\n\t\t\t$.each([\"_open\",\"_close\",\"\"], function (i,n) { \r\n\t\t\t\tvar\r\n\t\t\t\t\tsName\t\t= \"fxName\"+n\r\n\t\t\t\t,\tsSpeed\t\t= \"fxSpeed\"+n\r\n\t\t\t\t,\tsSettings\t= \"fxSettings\"+n\r\n\t\t\t\t;\r\n\t\t\t\t// recalculate fxName according to specificity rules\r\n\t\t\t\to[sName] =\r\n\t\t\t\t\topts[pane][sName]\t\t// opts.west.fxName_open\r\n\t\t\t\t||\topts[pane].fxName\t\t// opts.west.fxName\r\n\t\t\t\t||\topts.defaults[sName]\t// opts.defaults.fxName_open\r\n\t\t\t\t||\topts.defaults.fxName\t// opts.defaults.fxName\r\n\t\t\t\t||\to[sName]\t\t\t\t// options.west.fxName_open\r\n\t\t\t\t||\to.fxName\t\t\t\t// options.west.fxName\r\n\t\t\t\t||\tdefs[sName]\t\t\t\t// options.defaults.fxName_open\r\n\t\t\t\t||\tdefs.fxName\t\t\t\t// options.defaults.fxName\r\n\t\t\t\t||\t\"none\"\r\n\t\t\t\t;\r\n\t\t\t\t// validate fxName to be sure is a valid effect\r\n\t\t\t\tvar fxName = o[sName];\r\n\t\t\t\tif (fxName == \"none\" || !$.effects || !$.effects[fxName] || (!effects[fxName] && !o[sSettings] && !o.fxSettings))\r\n\t\t\t\t\tfxName = o[sName] = \"none\"; // effect not loaded, OR undefined FX AND fxSettings not passed\r\n\t\t\t\t// set vars for effects subkeys to simplify logic\r\n\t\t\t\tvar\r\n\t\t\t\t\tfx = effects[fxName]\t|| {} // effects.slide\r\n\t\t\t\t,\tfx_all\t= fx.all\t\t|| {} // effects.slide.all\r\n\t\t\t\t,\tfx_pane\t= fx[pane]\t\t|| {} // effects.slide.west\r\n\t\t\t\t;\r\n\t\t\t\t// RECREATE the fxSettings[_open|_close] keys using specificity rules\r\n\t\t\t\to[sSettings] = $.extend(\r\n\t\t\t\t\t{}\r\n\t\t\t\t,\tfx_all\t\t\t\t\t\t// effects.slide.all\r\n\t\t\t\t,\tfx_pane\t\t\t\t\t\t// effects.slide.west\r\n\t\t\t\t,\tdefs.fxSettings || {}\t\t// options.defaults.fxSettings\r\n\t\t\t\t,\tdefs[sSettings] || {}\t\t// options.defaults.fxSettings_open\r\n\t\t\t\t,\to.fxSettings\t\t\t\t// options.west.fxSettings\r\n\t\t\t\t,\to[sSettings]\t\t\t\t// options.west.fxSettings_open\r\n\t\t\t\t,\topts.defaults.fxSettings\t// opts.defaults.fxSettings\r\n\t\t\t\t,\topts.defaults[sSettings] || {} // opts.defaults.fxSettings_open\r\n\t\t\t\t,\topts[pane].fxSettings\t\t// opts.west.fxSettings\r\n\t\t\t\t,\topts[pane][sSettings] || {}\t// opts.west.fxSettings_open\r\n\t\t\t\t);\r\n\t\t\t\t// recalculate fxSpeed according to specificity rules\r\n\t\t\t\to[sSpeed] =\r\n\t\t\t\t\topts[pane][sSpeed]\t\t// opts.west.fxSpeed_open\r\n\t\t\t\t||\topts[pane].fxSpeed\t\t// opts.west.fxSpeed (pane-default)\r\n\t\t\t\t||\topts.defaults[sSpeed]\t// opts.defaults.fxSpeed_open\r\n\t\t\t\t||\topts.defaults.fxSpeed\t// opts.defaults.fxSpeed\r\n\t\t\t\t||\to[sSpeed]\t\t\t\t// options.west.fxSpeed_open\r\n\t\t\t\t||\to[sSettings].duration\t// options.west.fxSettings_open.duration\r\n\t\t\t\t||\to.fxSpeed\t\t\t\t// options.west.fxSpeed\r\n\t\t\t\t||\to.fxSettings.duration\t// options.west.fxSettings.duration\r\n\t\t\t\t||\tdefs.fxSpeed\t\t\t// options.defaults.fxSpeed\r\n\t\t\t\t||\tdefs.fxSettings.duration// options.defaults.fxSettings.duration\r\n\t\t\t\t||\tfx_pane.duration\t\t// effects.slide.west.duration\r\n\t\t\t\t||\tfx_all.duration\t\t\t// effects.slide.all.duration\r\n\t\t\t\t||\t\"normal\"\t\t\t\t// DEFAULT\r\n\t\t\t\t;\r\n\t\t\t\t// DEBUG: if (pane==\"east\") debugData( $.extend({}, {speed: o[sSpeed], fxSettings_duration: o[sSettings].duration}, o[sSettings]), pane+\".\"+sName+\" = \"+fxName );\r\n\t\t\t});\r\n\t\t});\r\n\t};\r\n\r\n\t/**\r\n\t * initPanes\r\n\t *\r\n\t * Initialize module objects, styling, size and position for all panes\r\n\t *\r\n\t * @callers  create()\r\n\t */\r\n\tvar initPanes = function () {\r\n\t\t// NOTE: do north & south FIRST so we can measure their height - do center LAST\r\n\t\t$.each(c.allPanes.split(\",\"), function() {\r\n\t\t\tvar \r\n\t\t\t\tpane\t= str(this)\r\n\t\t\t,\to\t\t= options[pane]\r\n\t\t\t,\ts\t\t= state[pane]\r\n\t\t\t,\tfx\t\t= s.fx\r\n\t\t\t,\tdir\t\t= c[pane].dir\r\n\t\t\t//\tif o.size is not > 0, then we will use MEASURE the pane and use that as it's 'size'\r\n\t\t\t,\tsize\t= o.size==\"auto\" || isNaN(o.size) ? 0 : o.size\r\n\t\t\t,\tminSize\t= o.minSize || 1\r\n\t\t\t,\tmaxSize\t= o.maxSize || 9999\r\n\t\t\t,\tspacing\t= o.spacing_open || 0\r\n\t\t\t,\tsel\t\t= o.paneSelector\r\n\t\t\t,\tisIE6\t= ($.browser.msie && $.browser.version < 7)\r\n\t\t\t,\tCSS\t\t= {}\r\n\t\t\t,\t$P, $C\r\n\t\t\t;\r\n\t\t\t$Cs[pane] = false; // init\r\n\r\n\t\t\tif (sel.substr(0,1)===\"#\") // ID selector\r\n\t\t\t\t// NOTE: elements selected 'by ID' DO NOT have to be 'children'\r\n\t\t\t\t$P = $Ps[pane] = $Container.find(sel+\":first\");\r\n\t\t\telse { // class or other selector\r\n\t\t\t\t$P = $Ps[pane] = $Container.children(sel+\":first\");\r\n\t\t\t\t// look for the pane nested inside a 'form' element\r\n\t\t\t\tif (!$P.length) $P = $Ps[pane] = $Container.children(\"form:first\").children(sel+\":first\");\r\n\t\t\t}\r\n\r\n\t\t\tif (!$P.length) {\r\n\t\t\t\t$Ps[pane] = false; // logic\r\n\t\t\t\treturn true; // SKIP to next\r\n\t\t\t}\r\n\r\n\t\t\t// add basic classes & attributes\r\n\t\t\t$P\r\n\t\t\t\t.attr(\"pane\", pane) // add pane-identifier\r\n\t\t\t\t.addClass( o.paneClass +\" \"+ o.paneClass+\"-\"+pane ) // default = \"ui-layout-pane ui-layout-pane-west\" - may be a dupe of 'paneSelector'\r\n\t\t\t;\r\n\r\n\t\t\t// init pane-logic vars, etc.\r\n\t\t\tif (pane != \"center\") {\r\n\t\t\t\ts.isClosed  = false; // true = pane is closed\r\n\t\t\t\ts.isSliding = false; // true = pane is currently open by 'sliding' over adjacent panes\r\n\t\t\t\ts.isResizing= false; // true = pane is in process of being resized\r\n\t\t\t\ts.isHidden\t= false; // true = pane is hidden - no spacing, resizer or toggler is visible!\r\n\t\t\t\ts.noRoom\t= false; // true = pane 'automatically' hidden due to insufficient room - will unhide automatically\r\n\t\t\t\t// create special keys for internal use\r\n\t\t\t\tc[pane].pins = [];   // used to track and sync 'pin-buttons' for border-panes\r\n\t\t\t}\r\n\r\n\t\t\tCSS = $.extend({ visibility: \"visible\", display: \"block\" }, c.defaults.cssReq, c[pane].cssReq );\r\n\t\t\tif (o.applyDefaultStyles) $.extend( CSS, c.defaults.cssDef, c[pane].cssDef ); // cosmetic defaults\r\n\t\t\t$P.css(CSS); // add base-css BEFORE 'measuring' to calc size & position\r\n\t\t\tCSS = {};\t// reset var\r\n\r\n\t\t\t// set css-position to account for container borders & padding\r\n\t\t\tswitch (pane) {\r\n\t\t\t\tcase \"north\": \tCSS.top \t= cDims.top;\r\n\t\t\t\t\t\t\t\tCSS.left \t= cDims.left;\r\n\t\t\t\t\t\t\t\tCSS.right\t= cDims.right;\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"south\": \tCSS.bottom\t= cDims.bottom;\r\n\t\t\t\t\t\t\t\tCSS.left \t= cDims.left;\r\n\t\t\t\t\t\t\t\tCSS.right \t= cDims.right;\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"west\": \tCSS.left \t= cDims.left; // top, bottom & height set by sizeMidPanes()\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"east\": \tCSS.right \t= cDims.right; // ditto\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\tcase \"center\":\t// top, left, width & height set by sizeMidPanes()\r\n\t\t\t}\r\n\r\n\t\t\tif (dir == \"horz\") { // north or south pane\r\n\t\t\t\tif (size === 0 || size == \"auto\") {\r\n\t\t\t\t\t$P.css({ height: \"auto\" });\r\n\t\t\t\t\tsize = $P.outerHeight();\r\n\t\t\t\t}\r\n\t\t\t\tsize = max(size, minSize);\r\n\t\t\t\tsize = min(size, maxSize);\r\n\t\t\t\tsize = min(size, cDims.innerHeight - spacing);\r\n\t\t\t\tCSS.height = max(1, cssH(pane, size));\r\n\t\t\t\ts.size = size; // update state\r\n\t\t\t\t// make sure minSize is sufficient to avoid errors\r\n\t\t\t\ts.maxSize = maxSize; // init value\r\n\t\t\t\ts.minSize = max(minSize, size - CSS.height + 1); // = pane.outerHeight when css.height = 1px\r\n\t\t\t\t// handle IE6\r\n\t\t\t\t//if (isIE6) CSS.width = cssW($P, cDims.innerWidth);\r\n\t\t\t\t$P.css(CSS); // apply size & position\r\n\t\t\t}\r\n\t\t\telse if (dir == \"vert\") { // east or west pane\r\n\t\t\t\tif (size === 0 || size == \"auto\") {\r\n\t\t\t\t\t$P.css({ width: \"auto\", float: \"left\" }); // float = FORCE pane to auto-size\r\n\t\t\t\t\tsize = $P.outerWidth();\r\n\t\t\t\t\t$P.css({ float: \"none\" }); // RESET\r\n\t\t\t\t}\r\n\t\t\t\tsize = max(size, minSize);\r\n\t\t\t\tsize = min(size, maxSize);\r\n\t\t\t\tsize = min(size, cDims.innerWidth - spacing);\r\n\t\t\t\tCSS.width = max(1, cssW(pane, size));\r\n\t\t\t\ts.size = size; // update state\r\n\t\t\t\ts.maxSize = maxSize; // init value\r\n\t\t\t\t// make sure minSize is sufficient to avoid errors\r\n\t\t\t\ts.minSize = max(minSize, size - CSS.width + 1); // = pane.outerWidth when css.width = 1px\r\n\t\t\t\t$P.css(CSS); // apply size - top, bottom & height set by sizeMidPanes\r\n\t\t\t\tsizeMidPanes(pane, null, true); // true = onInit\r\n\t\t\t}\r\n\t\t\telse if (pane == \"center\") {\r\n\t\t\t\t$P.css(CSS); // top, left, width & height set by sizeMidPanes...\r\n\t\t\t\tsizeMidPanes(\"center\", null, true); // true = onInit\r\n\t\t\t}\r\n\r\n\t\t\t// close or hide the pane if specified in settings\r\n\t\t\tif (o.initClosed && o.closable) {\r\n\t\t\t\t$P.hide().addClass(\"closed\");\r\n\t\t\t\ts.isClosed = true;\r\n\t\t\t}\r\n\t\t\telse if (o.initHidden || o.initClosed) {\r\n\t\t\t\thide(pane, true); // will be completely invisible - no resizer or spacing\r\n\t\t\t\ts.isHidden = true;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t\t$P.addClass(\"open\");\r\n\r\n\t\t\t// check option for auto-handling of pop-ups & drop-downs\r\n\t\t\tif (o.showOverflowOnHover)\r\n\t\t\t\t$P.hover( allowOverflow, resetOverflow );\r\n\r\n\t\t\t/*\r\n\t\t\t *\tsee if this pane has a 'content element' that we need to auto-size\r\n\t\t\t */\r\n\t\t\tif (o.contentSelector) {\r\n\t\t\t\t$C = $Cs[pane] = $P.children(o.contentSelector+\":first\"); // match 1-element only\r\n\t\t\t\tif (!$C.length) {\r\n\t\t\t\t\t$Cs[pane] = false;\r\n\t\t\t\t\treturn true; // SKIP to next\r\n\t\t\t\t}\r\n\t\t\t\t$C.css( c.content.cssReq );\r\n\t\t\t\tif (o.applyDefaultStyles) $C.css( c.content.cssDef ); // cosmetic defaults\r\n\t\t\t\t// NO PANE-SCROLLING when there is a content-div\r\n\t\t\t\t$P.css({ overflow: \"hidden\" });\r\n\t\t\t}\r\n\t\t});\r\n\t};\r\n\r\n\t/**\r\n\t * initHandles\r\n\t *\r\n\t * Initialize module objects, styling, size and position for all resize bars and toggler buttons\r\n\t *\r\n\t * @callers  create()\r\n\t */\r\n\tvar initHandles = function () {\r\n\t\t// create toggler DIVs for each pane, and set object pointers for them, eg: $R.north = north toggler DIV\r\n\t\t$.each(c.borderPanes.split(\",\"), function() {\r\n\t\t\tvar \r\n\t\t\t\tpane\t= str(this)\r\n\t\t\t,\to\t\t= options[pane]\r\n\t\t\t,\ts\t\t= state[pane]\r\n\t\t\t,\trClass\t= o.resizerClass\r\n\t\t\t,\ttClass\t= o.togglerClass\r\n\t\t\t,\t$P\t\t= $Ps[pane]\r\n\t\t\t;\r\n\t\t\t$Rs[pane] = false; // INIT\r\n\t\t\t$Ts[pane] = false;\r\n\r\n\t\t\tif (!$P || (!o.closable && !o.resizable)) return; // pane does not exist - skip\r\n\r\n\t\t\tvar \r\n\t\t\t\tedge\t= c[pane].edge\r\n\t\t\t,\tisOpen\t= $P.is(\":visible\")\r\n\t\t\t,\tspacing\t= (isOpen ? o.spacing_open : o.spacing_closed)\r\n\t\t\t,\t_pane\t= \"-\"+ pane // used for classNames\r\n\t\t\t,\t_state\t= (isOpen ? \"-open\" : \"-closed\") // used for classNames\r\n\t\t\t,\t$R, $T\r\n\t\t\t;\r\n\t\t\t// INIT RESIZER BAR\r\n\t\t\t$R = $Rs[pane] = $(\"<span></span>\");\r\n\t\r\n\t\t\tif (isOpen && o.resizable)\r\n\t\t\t\t; // this is handled by initResizable\r\n\t\t\telse if (!isOpen && o.slidable)\r\n\t\t\t\t$R.attr(\"title\", o.sliderTip).css(\"cursor\", o.sliderCursor);\r\n\t\r\n\t\t\t$R\r\n\t\t\t\t// if paneSelector is an ID, then create a matching ID for the resizer, eg: \"#paneLeft\" => \"paneLeft-resizer\"\r\n\t\t\t\t.attr(\"id\", (o.paneSelector.substr(0,1)==\"#\" ? o.paneSelector.substr(1) + \"-resizer\" : \"\"))\r\n\t\t\t\t.attr(\"resizer\", pane) // so we can read this from the resizer\r\n\t\t\t\t.css(c.resizers.cssReq) // add base/required styles\r\n\t\t\t\t// POSITION of resizer bar - allow for container border & padding\r\n\t\t\t\t.css(edge, cDims[edge] + getPaneSize(pane))\r\n\t\t\t\t// ADD CLASSNAMES - eg: class=\"resizer resizer-west resizer-open\"\r\n\t\t\t\t.addClass( rClass +\" \"+ rClass+_pane +\" \"+ rClass+_state +\" \"+ rClass+_pane+_state )\r\n\t\t\t\t.appendTo($Container) // append DIV to container\r\n\t\t\t;\r\n\t\t\t // ADD VISUAL STYLES\r\n\t\t\tif (o.applyDefaultStyles)\r\n\t\t\t\t$R.css(c.resizers.cssDef);\r\n\r\n\t\t\tif (o.closable) {\r\n\t\t\t\t// INIT COLLAPSER BUTTON\r\n\t\t\t\t$T = $Ts[pane] = $(\"<div></div>\");\r\n\t\t\t\t$T\r\n\t\t\t\t\t// if paneSelector is an ID, then create a matching ID for the resizer, eg: \"#paneLeft\" => \"paneLeft-toggler\"\r\n\t\t\t\t\t.attr(\"id\", (o.paneSelector.substr(0,1)==\"#\" ? o.paneSelector.substr(1) + \"-toggler\" : \"\"))\r\n\t\t\t\t\t.css(c.togglers.cssReq) // add base/required styles\r\n\t\t\t\t\t.attr(\"title\", (isOpen ? o.togglerTip_open : o.togglerTip_closed))\r\n\t\t\t\t\t.click(function(evt){ toggle(pane); evt.stopPropagation(); })\r\n\t\t\t\t\t.mouseover(function(evt){ evt.stopPropagation(); }) // prevent resizer event\r\n\t\t\t\t\t// ADD CLASSNAMES - eg: class=\"toggler toggler-west toggler-west-open\"\r\n\t\t\t\t\t.addClass( tClass +\" \"+ tClass+_pane +\" \"+ tClass+_state +\" \"+ tClass+_pane+_state )\r\n\t\t\t\t\t.appendTo($R) // append SPAN to resizer DIV\r\n\t\t\t\t;\r\n\r\n\t\t\t\t// ADD INNER-SPANS TO TOGGLER\r\n\t\t\t\tif (o.togglerContent_open) // ui-layout-open\r\n\t\t\t\t\t$(\"<span>\"+ o.togglerContent_open +\"</span>\")\r\n\t\t\t\t\t\t.addClass(\"content content-open\")\r\n\t\t\t\t\t\t.css(\"display\", s.isClosed ? \"none\" : \"block\")\r\n\t\t\t\t\t\t.appendTo( $T )\r\n\t\t\t\t\t;\r\n\t\t\t\tif (o.togglerContent_closed) // ui-layout-closed\r\n\t\t\t\t\t$(\"<span>\"+ o.togglerContent_closed +\"</span>\")\r\n\t\t\t\t\t\t.addClass(\"content content-closed\")\r\n\t\t\t\t\t\t.css(\"display\", s.isClosed ? \"block\" : \"none\")\r\n\t\t\t\t\t\t.appendTo( $T )\r\n\t\t\t\t\t;\r\n\r\n\t\t\t\t // ADD BASIC VISUAL STYLES\r\n\t\t\t\tif (o.applyDefaultStyles)\r\n\t\t\t\t\t$T.css(c.togglers.cssDef);\r\n\r\n\t\t\t\tif (!isOpen) bindStartSlidingEvent(pane, true); // will enable if state.PANE.isSliding = true\r\n\t\t\t}\r\n\r\n\t\t});\r\n\r\n\t\t// SET ALL HANDLE SIZES & LENGTHS\r\n\t\tsizeHandles(\"all\", true); // true = onInit\r\n\t};\r\n\r\n\t/**\r\n\t * initResizable\r\n\t *\r\n\t * Add resize-bars to all panes that specify it in options\r\n\t *\r\n\t * @dependancies  $.fn.resizable - will abort if not found\r\n\t * @callers  create()\r\n\t */\r\n\tvar initResizable = function () {\r\n\t\tvar\r\n\t\t\tdraggingAvailable = (typeof $.fn.draggable == \"function\")\r\n\t\t,\tminPosition, maxPosition, edge // set in start()\r\n\t\t;\r\n\r\n\t\t$.each(c.borderPanes.split(\",\"), function() {\r\n\t\t\tvar \r\n\t\t\t\tpane\t= str(this)\r\n\t\t\t,\to\t\t= options[pane]\r\n\t\t\t,\ts\t\t= state[pane]\r\n\t\t\t;\r\n\t\t\tif (!draggingAvailable || !$Ps[pane] || !o.resizable) {\r\n\t\t\t\to.resizable = false;\r\n\t\t\t\treturn true; // skip to next\r\n\t\t\t}\r\n\r\n\t\t\tvar \r\n\t\t\t\trClass\t\t\t\t= o.resizerClass\r\n\t\t\t//\t'drag' classes are applied to the ORIGINAL resizer-bar while dragging is in process\r\n\t\t\t,\tdragClass\t\t\t= rClass+\"-drag\"\t\t\t// resizer-drag\r\n\t\t\t,\tdragPaneClass\t\t= rClass+\"-\"+pane+\"-drag\"\t// resizer-north-drag\r\n\t\t\t//\t'dragging' class is applied to the CLONED resizer-bar while it is being dragged\r\n\t\t\t,\tdraggingClass\t\t= rClass+\"-dragging\"\t\t// resizer-dragging\r\n\t\t\t,\tdraggingPaneClass\t= rClass+\"-\"+pane+\"-dragging\" // resizer-north-dragging\r\n\t\t\t,\tdraggingClassSet\t= false \t\t\t\t\t// logic var\r\n\t\t\t,\t$P \t\t\t\t\t= $Ps[pane]\r\n\t\t\t,\t$R\t\t\t\t\t= $Rs[pane]\r\n\t\t\t;\r\n\r\n\t\t\tif (!s.isClosed)\r\n\t\t\t\t$R\r\n\t\t\t\t\t.attr(\"title\", o.resizerTip)\r\n\t\t\t\t\t.css(\"cursor\", o.resizerCursor) // n-resize, s-resize, etc\r\n\t\t\t\t;\r\n\r\n\t\t\t$R.draggable({\r\n\t\t\t\tcontainment:\t$Container[0] // limit resizing to layout container\r\n\t\t\t,\taxis:\t\t\t(c[pane].dir==\"horz\" ? \"y\" : \"x\") // limit resizing to horz or vert axis\r\n\t\t\t,\tdelay:\t\t\t200\r\n\t\t\t,\tdistance:\t\t1\r\n\t\t\t//\tbasic format for helper - style it using class: .ui-draggable-dragging\r\n\t\t\t,\thelper:\t\t\t\"clone\"\r\n\t\t\t,\topacity:\t\to.resizerDragOpacity\r\n\t\t\t//,\tiframeFix:\t\to.draggableIframeFix // TODO: consider using when bug is fixed\r\n\t\t\t,\tzIndex:\t\t\tc.zIndex.resizing\r\n\r\n\t\t\t,\tstart: function (e, ui) {\r\n\t\t\t\t\t// onresize_start callback - will CANCEL hide if returns false\r\n\t\t\t\t\t// TODO: CONFIRM that dragging can be cancelled like this???\r\n\t\t\t\t\tif (false === execUserCallback(pane, o.onresize_start)) return false;\r\n\r\n\t\t\t\t\ts.isResizing = true; // prevent pane from closing while resizing\r\n\t\t\t\t\tclearTimer(pane, \"closeSlider\"); // just in case already triggered\r\n\r\n\t\t\t\t\t$R.addClass( dragClass +\" \"+ dragPaneClass ); // add drag classes\r\n\t\t\t\t\tdraggingClassSet = false; // reset logic var - see drag()\r\n\r\n\t\t\t\t\t// SET RESIZING LIMITS - used in drag()\r\n\t\t\t\t\tvar resizerWidth = (pane==\"east\" || pane==\"south\" ? o.spacing_open : 0);\r\n\t\t\t\t\tsetPaneMinMaxSizes(pane); // update pane-state\r\n\t\t\t\t\ts.minPosition -= resizerWidth;\r\n\t\t\t\t\ts.maxPosition -= resizerWidth;\r\n\t\t\t\t\tedge = (c[pane].dir==\"horz\" ? \"top\" : \"left\");\r\n\r\n\t\t\t\t\t// MASK PANES WITH IFRAMES OR OTHER TROUBLESOME ELEMENTS\r\n\t\t\t\t\t$(o.maskIframesOnResize === true ? \"iframe\" : o.maskIframesOnResize).each(function() {\t\t\t\t\t\r\n\t\t\t\t\t\t$('<div class=\"ui-layout-mask\"/>')\r\n\t\t\t\t\t\t\t.css({\r\n\t\t\t\t\t\t\t\tbackground:\t\"#fff\"\r\n\t\t\t\t\t\t\t,\topacity:\t\"0.001\"\r\n\t\t\t\t\t\t\t,\tzIndex:\t\t9\r\n\t\t\t\t\t\t\t,\tposition:\t\"absolute\"\r\n\t\t\t\t\t\t\t,\twidth:\t\tthis.offsetWidth+\"px\"\r\n\t\t\t\t\t\t\t,\theight:\t\tthis.offsetHeight+\"px\"\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t\t.css($(this).offset()) // top & left\r\n\t\t\t\t\t\t\t.appendTo(this.parentNode) // put div INSIDE pane to avoid zIndex issues\r\n\t\t\t\t\t\t;\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\r\n\t\t\t,\tdrag: function (e, ui) {\r\n\t\t\t\t\tif (!draggingClassSet) { // can only add classes after clone has been added to the DOM\r\n\t\t\t\t\t\t$(\".ui-draggable-dragging\")\r\n\t\t\t\t\t\t\t.addClass( draggingClass +\" \"+ draggingPaneClass ) // add dragging classes\r\n\t\t\t\t\t\t\t.children().css(\"visibility\",\"hidden\") // hide toggler inside dragged resizer-bar\r\n\t\t\t\t\t\t;\r\n\t\t\t\t\t\tdraggingClassSet = true;\r\n\t\t\t\t\t\t// draggable bug!? RE-SET zIndex to prevent E/W resize-bar showing through N/S pane!\r\n\t\t\t\t\t\tif (s.isSliding) $Ps[pane].css(\"zIndex\", c.zIndex.sliding);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// CONTAIN RESIZER-BAR TO RESIZING LIMITS\r\n\t\t\t\t\tif\t\t(ui.position[edge] < s.minPosition) ui.position[edge] = s.minPosition;\r\n\t\t\t\t\telse if (ui.position[edge] > s.maxPosition) ui.position[edge] = s.maxPosition;\r\n\t\t\t\t}\r\n\r\n\t\t\t,\tstop: function (e, ui) {\r\n\t\t\t\t\tvar \r\n\t\t\t\t\t\tdragPos\t= ui.position\r\n\t\t\t\t\t,\tresizerPos\r\n\t\t\t\t\t,\tnewSize\r\n\t\t\t\t\t;\r\n\t\t\t\t\t$R.removeClass( dragClass +\" \"+ dragPaneClass ); // remove drag classes\r\n\t\r\n\t\t\t\t\tswitch (pane) {\r\n\t\t\t\t\t\tcase \"north\":\tresizerPos = dragPos.top; break;\r\n\t\t\t\t\t\tcase \"west\":\tresizerPos = dragPos.left; break;\r\n\t\t\t\t\t\tcase \"south\":\tresizerPos = cDims.outerHeight - dragPos.top - $R.outerHeight(); break;\r\n\t\t\t\t\t\tcase \"east\":\tresizerPos = cDims.outerWidth - dragPos.left - $R.outerWidth(); break;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t// remove container margin from resizer position to get the pane size\r\n\t\t\t\t\tnewSize = resizerPos - cDims[ c[pane].edge ];\r\n\r\n\t\t\t\t\tsizePane(pane, newSize);\r\n\r\n\t\t\t\t\t// UN-MASK PANES MASKED IN drag.start\r\n\t\t\t\t\t$(\"div.ui-layout-mask\").remove(); // Remove iframe masks\t\r\n\r\n\t\t\t\t\ts.isResizing = false;\r\n\t\t\t\t}\r\n\r\n\t\t\t});\r\n\t\t});\r\n\t};\r\n\r\n\r\n\r\n/*\r\n * ###########################\r\n *       ACTION METHODS\r\n * ###########################\r\n */\r\n\r\n\t/**\r\n\t * hide / show\r\n\t *\r\n\t * Completely 'hides' a pane, including its spacing - as if it does not exist\r\n\t * The pane is not actually 'removed' from the source, so can use 'show' to un-hide it\r\n\t *\r\n\t * @param String  pane   The pane being hidden, ie: north, south, east, or west\r\n\t */\r\n\tvar hide = function (pane, onInit) {\r\n\t\tvar\r\n\t\t\to\t= options[pane]\r\n\t\t,\ts\t= state[pane]\r\n\t\t,\t$P\t= $Ps[pane]\r\n\t\t,\t$R\t= $Rs[pane]\r\n\t\t;\r\n\t\tif (!$P || s.isHidden) return; // pane does not exist OR is already hidden\r\n\r\n\t\t// onhide_start callback - will CANCEL hide if returns false\r\n\t\tif (false === execUserCallback(pane, o.onhide_start)) return;\r\n\r\n\t\ts.isSliding = false; // just in case\r\n\r\n\t\t// now hide the elements\r\n\t\tif ($R) $R.hide(); // hide resizer-bar\r\n\t\tif (onInit || s.isClosed) {\r\n\t\t\ts.isClosed = true; // to trigger open-animation on show()\r\n\t\t\ts.isHidden  = true;\r\n\t\t\t$P.hide(); // no animation when loading page\r\n\t\t\tsizeMidPanes(c[pane].dir == \"horz\" ? \"all\" : \"center\");\r\n\t\t\texecUserCallback(pane, o.onhide_end || o.onhide);\r\n\t\t}\r\n\t\telse {\r\n\t\t\ts.isHiding = true; // used by onclose\r\n\t\t\tclose(pane, false); // adjust all panes to fit\r\n\t\t\t//s.isHidden  = true; - will be set by close - if not cancelled\r\n\t\t}\r\n\t};\r\n\r\n\tvar show = function (pane, openPane) {\r\n\t\tvar\r\n\t\t\to\t= options[pane]\r\n\t\t,\ts\t= state[pane]\r\n\t\t,\t$P\t= $Ps[pane]\r\n\t\t,\t$R\t= $Rs[pane]\r\n\t\t;\r\n\t\tif (!$P || !s.isHidden) return; // pane does not exist OR is not hidden\r\n\r\n\t\t// onhide_start callback - will CANCEL hide if returns false\r\n\t\tif (false === execUserCallback(pane, o.onshow_start)) return;\r\n\r\n\t\ts.isSliding = false; // just in case\r\n\t\ts.isShowing = true; // used by onopen/onclose\r\n\t\t//s.isHidden  = false; - will be set by open/close - if not cancelled\r\n\r\n\t\t// now show the elements\r\n\t\tif ($R && o.spacing_open > 0) $R.show();\r\n\t\tif (openPane === false)\r\n\t\t\tclose(pane, true); // true = force\r\n\t\telse\r\n\t\t\topen(pane); // adjust all panes to fit\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * toggle\r\n\t *\r\n\t * Toggles a pane open/closed by calling either open or close\r\n\t *\r\n\t * @param String  pane   The pane being toggled, ie: north, south, east, or west\r\n\t */\r\n\tvar toggle = function (pane) {\r\n\t\tvar s = state[pane];\r\n\t\tif (s.isHidden)\r\n\t\t\tshow(pane); // will call 'open' after unhiding it\r\n\t\telse if (s.isClosed)\r\n\t\t\topen(pane);\r\n\t\telse\r\n\t\t\tclose(pane);\r\n\t};\r\n\r\n\t/**\r\n\t * close\r\n\t *\r\n\t * Close the specified pane (animation optional), and resize all other panes as needed\r\n\t *\r\n\t * @param String  pane   The pane being closed, ie: north, south, east, or west\r\n\t */\r\n\tvar close = function (pane, force, noAnimation) {\r\n\t\tvar \r\n\t\t\t$P\t\t= $Ps[pane]\r\n\t\t,\t$R\t\t= $Rs[pane]\r\n\t\t,\t$T\t\t= $Ts[pane]\r\n\t\t,\to\t\t= options[pane]\r\n\t\t,\ts\t\t= state[pane]\r\n\t\t,\tdoFX\t= !noAnimation && !s.isClosed && (o.fxName_close != \"none\")\r\n\t\t,\tedge\t= c[pane].edge\r\n\t\t,\trClass\t= o.resizerClass\r\n\t\t,\ttClass\t= o.togglerClass\r\n\t\t,\t_pane\t= \"-\"+ pane // used for classNames\r\n\t\t,\t_open\t= \"-open\"\r\n\t\t,\t_sliding= \"-sliding\"\r\n\t\t,\t_closed\t= \"-closed\"\r\n\t\t// \ttransfer logic vars to temp vars\r\n\t\t,\tisShowing = s.isShowing\r\n\t\t,\tisHiding = s.isHiding\r\n\t\t;\r\n\t\t// now clear the logic vars\r\n\t\tdelete s.isShowing;\r\n\t\tdelete s.isHiding;\r\n\r\n\t\tif (!$P || (!o.resizable && !o.closable)) return; // invalid request\r\n\t\telse if (!force && s.isClosed && !isShowing) return; // already closed\r\n\r\n\t\tif (c.isLayoutBusy) { // layout is 'busy' - probably with an animation\r\n\t\t\tsetFlowCallback(\"close\", pane, force); // set a callback for this action, if possible\r\n\t\t\treturn; // ABORT \r\n\t\t}\r\n\r\n\t\t// onclose_start callback - will CANCEL hide if returns false\r\n\t\t// SKIP if just 'showing' a hidden pane as 'closed'\r\n\t\tif (!isShowing && false === execUserCallback(pane, o.onclose_start)) return;\r\n\r\n\t\t// SET flow-control flags\r\n\t\tc[pane].isMoving = true;\r\n\t\tc.isLayoutBusy = true;\r\n\r\n\t\ts.isClosed = true;\r\n\t\t// update isHidden BEFORE sizing panes\r\n\t\tif (isHiding) s.isHidden = true;\r\n\t\telse if (isShowing) s.isHidden = false;\r\n\r\n\t\t// sync any 'pin buttons'\r\n\t\tsyncPinBtns(pane, false);\r\n\r\n\t\t// resize panes adjacent to this one\r\n\t\tif (!s.isSliding) sizeMidPanes(c[pane].dir == \"horz\" ? \"all\" : \"center\");\r\n\r\n\t\t// if this pane has a resizer bar, move it now\r\n\t\tif ($R) {\r\n\t\t\t$R\r\n\t\t\t\t.css(edge, cDims[edge]) // move the resizer bar\r\n\t\t\t\t.removeClass( rClass+_open +\" \"+ rClass+_pane+_open )\r\n\t\t\t\t.removeClass( rClass+_sliding +\" \"+ rClass+_pane+_sliding )\r\n\t\t\t\t.addClass( rClass+_closed +\" \"+ rClass+_pane+_closed )\r\n\t\t\t;\r\n\t\t\t// DISABLE 'resizing' when closed - do this BEFORE bindStartSlidingEvent\r\n\t\t\tif (o.resizable)\r\n\t\t\t\t$R\r\n\t\t\t\t\t.draggable(\"disable\")\r\n\t\t\t\t\t.css(\"cursor\", \"default\")\r\n\t\t\t\t\t.attr(\"title\",\"\")\r\n\t\t\t\t;\r\n\t\t\t// if pane has a toggler button, adjust that too\r\n\t\t\tif ($T) {\r\n\t\t\t\t$T\r\n\t\t\t\t\t.removeClass( tClass+_open +\" \"+ tClass+_pane+_open )\r\n\t\t\t\t\t.addClass( tClass+_closed +\" \"+ tClass+_pane+_closed )\r\n\t\t\t\t\t.attr(\"title\", o.togglerTip_closed) // may be blank\r\n\t\t\t\t;\r\n\t\t\t}\r\n\t\t\tsizeHandles(); // resize 'length' and position togglers for adjacent panes\r\n\t\t}\r\n\r\n\t\t// ANIMATE 'CLOSE' - if no animation, then was ALREADY shown above\r\n\t\tif (doFX) {\r\n\t\t\tlockPaneForFX(pane, true); // need to set left/top so animation will work\r\n\t\t\t$P.hide( o.fxName_close, o.fxSettings_close, o.fxSpeed_close, function () {\r\n\t\t\t\tlockPaneForFX(pane, false); // undo\r\n\t\t\t\tif (!s.isClosed) return; // pane was opened before animation finished!\r\n\t\t\t\tclose_2();\r\n\t\t\t});\r\n\t\t}\r\n\t\telse {\r\n\t\t\t$P.hide(); // just hide pane NOW\r\n\t\t\tclose_2();\r\n\t\t}\r\n\r\n\t\t// SUBROUTINE\r\n\t\tfunction close_2 () {\r\n\t\t\tbindStartSlidingEvent(pane, true); // will enable if state.PANE.isSliding = true\r\n\r\n\t\t\t// onclose callback - UNLESS just 'showing' a hidden pane as 'closed'\r\n\t\t\tif (!isShowing)\texecUserCallback(pane, o.onclose_end || o.onclose);\r\n\t\t\t// onhide OR onshow callback\r\n\t\t\tif (isShowing)\texecUserCallback(pane, o.onshow_end || o.onshow);\r\n\t\t\tif (isHiding)\texecUserCallback(pane, o.onhide_end || o.onhide);\r\n\r\n\t\t\t// internal flow-control callback\r\n\t\t\texecFlowCallback(pane);\r\n\t\t}\r\n\t};\r\n\r\n\t/**\r\n\t * open\r\n\t *\r\n\t * Open the specified pane (animation optional), and resize all other panes as needed\r\n\t *\r\n\t * @param String  pane   The pane being opened, ie: north, south, east, or west\r\n\t */\r\n\tvar open = function (pane, slide, noAnimation) {\r\n\t\tvar \r\n\t\t\t$P\t\t= $Ps[pane]\r\n\t\t,\t$R\t\t= $Rs[pane]\r\n\t\t,\t$T\t\t= $Ts[pane]\r\n\t\t,\to\t\t= options[pane]\r\n\t\t,\ts\t\t= state[pane]\r\n\t\t,\tdoFX\t= !noAnimation && s.isClosed && (o.fxName_open != \"none\")\r\n\t\t,\tedge\t= c[pane].edge\r\n\t\t,\trClass\t= o.resizerClass\r\n\t\t,\ttClass\t= o.togglerClass\r\n\t\t,\t_pane\t= \"-\"+ pane // used for classNames\r\n\t\t,\t_open\t= \"-open\"\r\n\t\t,\t_closed\t= \"-closed\"\r\n\t\t,\t_sliding= \"-sliding\"\r\n\t\t// \ttransfer logic var to temp var\r\n\t\t,\tisShowing = s.isShowing\r\n\t\t;\r\n\t\t// now clear the logic var\r\n\t\tdelete s.isShowing;\r\n\r\n\t\tif (!$P || (!o.resizable && !o.closable)) return; // invalid request\r\n\t\telse if (!s.isClosed && !s.isSliding) return; // already open\r\n\r\n\t\t// pane can ALSO be unhidden by just calling show(), so handle this scenario\r\n\t\tif (s.isHidden && !isShowing) {\r\n\t\t\tshow(pane, true);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (c.isLayoutBusy) { // layout is 'busy' - probably with an animation\r\n\t\t\tsetFlowCallback(\"open\", pane, slide); // set a callback for this action, if possible\r\n\t\t\treturn; // ABORT\r\n\t\t}\r\n\r\n\t\t// onopen_start callback - will CANCEL hide if returns false\r\n\t\tif (false === execUserCallback(pane, o.onopen_start)) return;\r\n\r\n\t\t// SET flow-control flags\r\n\t\tc[pane].isMoving = true;\r\n\t\tc.isLayoutBusy = true;\r\n\r\n\t\t// 'PIN PANE' - stop sliding\r\n\t\tif (s.isSliding && !slide) // !slide = 'open pane normally' - NOT sliding\r\n\t\t\tbindStopSlidingEvents(pane, false); // will set isSliding=false\r\n\r\n\t\ts.isClosed = false;\r\n\t\t// update isHidden BEFORE sizing panes\r\n\t\tif (isShowing) s.isHidden = false;\r\n\r\n\t\t// Container size may have changed - shrink the pane if now 'too big'\r\n\t\tsetPaneMinMaxSizes(pane); // update pane-state\r\n\t\tif (s.size > s.maxSize) // pane is too big! resize it before opening\r\n\t\t\t$P.css( c[pane].sizeType, max(1, cssSize(pane, s.maxSize)) );\r\n\r\n\t\tbindStartSlidingEvent(pane, false); // remove trigger event from resizer-bar\r\n\r\n\t\tif (doFX) { // ANIMATE\r\n\t\t\tlockPaneForFX(pane, true); // need to set left/top so animation will work\r\n\t\t\t$P.show( o.fxName_open, o.fxSettings_open, o.fxSpeed_open, function() {\r\n\t\t\t\tlockPaneForFX(pane, false); // undo\r\n\t\t\t\tif (s.isClosed) return; // pane was closed before animation finished!\r\n\t\t\t\topen_2(); // continue\r\n\t\t\t});\r\n\t\t}\r\n\t\telse {// no animation\r\n\t\t\t$P.show();\t// just show pane and...\r\n\t\t\topen_2();\t// continue\r\n\t\t}\r\n\r\n\t\t// SUBROUTINE\r\n\t\tfunction open_2 () {\r\n\t\t\t// NOTE: if isSliding, then other panes are NOT 'resized'\r\n\t\t\tif (!s.isSliding) // resize all panes adjacent to this one\r\n\t\t\t\tsizeMidPanes(c[pane].dir==\"vert\" ? \"center\" : \"all\");\r\n\r\n\t\t\t// if this pane has a toggler, move it now\r\n\t\t\tif ($R) {\r\n\t\t\t\t$R\r\n\t\t\t\t\t.css(edge, cDims[edge] + getPaneSize(pane)) // move the toggler\r\n\t\t\t\t\t.removeClass( rClass+_closed +\" \"+ rClass+_pane+_closed )\r\n\t\t\t\t\t.addClass( rClass+_open +\" \"+ rClass+_pane+_open )\r\n\t\t\t\t\t.addClass( !s.isSliding ? \"\" : rClass+_sliding +\" \"+ rClass+_pane+_sliding )\r\n\t\t\t\t;\r\n\t\t\t\tif (o.resizable)\r\n\t\t\t\t\t$R\r\n\t\t\t\t\t\t.draggable(\"enable\")\r\n\t\t\t\t\t\t.css(\"cursor\", o.resizerCursor)\r\n\t\t\t\t\t\t.attr(\"title\", o.resizerTip)\r\n\t\t\t\t\t;\r\n\t\t\t\telse\r\n\t\t\t\t\t$R.css(\"cursor\", \"default\"); // n-resize, s-resize, etc\r\n\t\t\t\t// if pane also has a toggler button, adjust that too\r\n\t\t\t\tif ($T) {\r\n\t\t\t\t\t$T\r\n\t\t\t\t\t\t.removeClass( tClass+_closed +\" \"+ tClass+_pane+_closed )\r\n\t\t\t\t\t\t.addClass( tClass+_open +\" \"+ tClass+_pane+_open )\r\n\t\t\t\t\t\t.attr(\"title\", o.togglerTip_open) // may be blank\r\n\t\t\t\t\t;\r\n\t\t\t\t}\r\n\t\t\t\tsizeHandles(\"all\"); // resize resizer & toggler sizes for all panes\r\n\t\t\t}\r\n\r\n\t\t\t// resize content every time pane opens - to be sure\r\n\t\t\tsizeContent(pane);\r\n\r\n\t\t\t// sync any 'pin buttons'\r\n\t\t\tsyncPinBtns(pane, !s.isSliding);\r\n\r\n\t\t\t// onopen callback\r\n\t\t\texecUserCallback(pane, o.onopen_end || o.onopen);\r\n\r\n\t\t\t// onshow callback\r\n\t\t\tif (isShowing) execUserCallback(pane, o.onshow_end || o.onshow);\r\n\r\n\t\t\t// internal flow-control callback\r\n\t\t\texecFlowCallback(pane);\r\n\t\t}\r\n\t};\r\n\t\r\n\r\n\t/**\r\n\t * lockPaneForFX\r\n\t *\r\n\t * Must set left/top on East/South panes so animation will work properly\r\n\t *\r\n\t * @param String  pane  The pane to lock, 'east' or 'south' - any other is ignored!\r\n\t * @param Boolean  doLock  true = set left/top, false = remove\r\n\t */\r\n\tvar lockPaneForFX = function (pane, doLock) {\r\n\t\tvar $P = $Ps[pane];\r\n\t\tif (doLock) {\r\n\t\t\t$P.css({ zIndex: c.zIndex.animation }); // overlay all elements during animation\r\n\t\t\tif (pane==\"south\")\r\n\t\t\t\t$P.css({ top: cDims.top + cDims.innerHeight - $P.outerHeight() });\r\n\t\t\telse if (pane==\"east\")\r\n\t\t\t\t$P.css({ left: cDims.left + cDims.innerWidth - $P.outerWidth() });\r\n\t\t}\r\n\t\telse {\r\n\t\t\tif (!state[pane].isSliding) $P.css({ zIndex: c.zIndex.pane_normal });\r\n\t\t\tif (pane==\"south\")\r\n\t\t\t\t$P.css({ top: \"auto\" });\r\n\t\t\telse if (pane==\"east\")\r\n\t\t\t\t$P.css({ left: \"auto\" });\r\n\t\t}\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * bindStartSlidingEvent\r\n\t *\r\n\t * Toggle sliding functionality of a specific pane on/off by adding removing 'slide open' trigger\r\n\t *\r\n\t * @callers  open(), close()\r\n\t * @param String  pane  The pane to enable/disable, 'north', 'south', etc.\r\n\t * @param Boolean  enable  Enable or Disable sliding?\r\n\t */\r\n\tvar bindStartSlidingEvent = function (pane, enable) {\r\n\t\tvar \r\n\t\t\to\t\t= options[pane]\r\n\t\t,\t$R\t\t= $Rs[pane]\r\n\t\t,\ttrigger\t= o.slideTrigger_open\r\n\t\t;\r\n\t\tif (!$R || !o.slidable) return;\r\n\t\t// make sure we have a valid event\r\n\t\tif (trigger != \"click\" && trigger != \"dblclick\" && trigger != \"mouseover\") trigger = \"click\";\r\n\t\t$R\r\n\t\t\t// add or remove trigger event\r\n\t\t\t[enable ? \"bind\" : \"unbind\"](trigger, slideOpen)\r\n\t\t\t// set the appropriate cursor & title/tip\r\n\t\t\t.css(\"cursor\", (enable ? o.sliderCursor: \"default\"))\r\n\t\t\t.attr(\"title\", (enable ? o.sliderTip : \"\"))\r\n\t\t;\r\n\t};\r\n\r\n\t/**\r\n\t * bindStopSlidingEvents\r\n\t *\r\n\t * Add or remove 'mouseout' events to 'slide close' when pane is 'sliding' open or closed\r\n\t * Also increases zIndex when pane is sliding open\r\n\t * See bindStartSlidingEvent for code to control 'slide open'\r\n\t *\r\n\t * @callers  slideOpen(), slideClosed()\r\n\t * @param String  pane  The pane to process, 'north', 'south', etc.\r\n\t * @param Boolean  isOpen  Is pane open or closed?\r\n\t */\r\n\tvar bindStopSlidingEvents = function (pane, enable) {\r\n\t\tvar \r\n\t\t\to\t\t= options[pane]\r\n\t\t,\ts\t\t= state[pane]\r\n\t\t,\ttrigger\t= o.slideTrigger_close\r\n\t\t,\taction\t= (enable ? \"bind\" : \"unbind\") // can't make 'unbind' work! - see disabled code below\r\n\t\t,\t$P\t\t= $Ps[pane]\r\n\t\t,\t$R\t\t= $Rs[pane]\r\n\t\t;\r\n\r\n\t\ts.isSliding = enable; // logic\r\n\t\tclearTimer(pane, \"closeSlider\"); // just in case\r\n\r\n\t\t// raise z-index when sliding\r\n\t\t$P.css({ zIndex: (enable ? c.zIndex.sliding : c.zIndex.pane_normal) });\r\n\t\t$R.css({ zIndex: (enable ? c.zIndex.sliding : c.zIndex.resizer_normal) });\r\n\r\n\t\t// make sure we have a valid event\r\n\t\tif (trigger != \"click\" && trigger != \"mouseout\") trigger = \"mouseout\";\r\n\r\n\t\t// when trigger is 'mouseout', must cancel timer when mouse moves between 'pane' and 'resizer'\r\n\t\tif (enable) { // BIND trigger events\r\n\t\t\t$P.bind(trigger, slideClosed );\r\n\t\t\t$R.bind(trigger, slideClosed );\r\n\t\t\tif (trigger = \"mouseout\") {\r\n\t\t\t\t$P.bind(\"mouseover\", cancelMouseOut );\r\n\t\t\t\t$R.bind(\"mouseover\", cancelMouseOut );\r\n\t\t\t}\r\n\t\t}\r\n\t\telse { // UNBIND trigger events\r\n\t\t\t// TODO: why does unbind of a 'single function' not work reliably?\r\n\t\t\t//$P[action](trigger, slideClosed );\r\n\t\t\t$P.unbind(trigger);\r\n\t\t\t$R.unbind(trigger);\r\n\t\t\tif (trigger = \"mouseout\") {\r\n\t\t\t\t//$P[action](\"mouseover\", cancelMouseOut );\r\n\t\t\t\t$P.unbind(\"mouseover\");\r\n\t\t\t\t$R.unbind(\"mouseover\");\r\n\t\t\t\tclearTimer(pane, \"closeSlider\");\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// SUBROUTINE for mouseout timer clearing\r\n\t\tfunction cancelMouseOut (evt) {\r\n\t\t\tclearTimer(pane, \"closeSlider\");\r\n\t\t\tevt.stopPropagation();\r\n\t\t}\r\n\t};\r\n\r\n\tvar slideOpen = function () {\r\n\t\tvar pane = $(this).attr(\"resizer\"); // attr added by initHandles\r\n\t\tif (state[pane].isClosed) { // skip if already open!\r\n\t\t\tbindStopSlidingEvents(pane, true); // pane is opening, so BIND trigger events to close it\r\n\t\t\topen(pane, true); // true = slide - ie, called from here!\r\n\t\t}\r\n\t};\r\n\r\n\tvar slideClosed = function () {\r\n\t\tvar\r\n\t\t\t$E = $(this)\r\n\t\t,\tpane = $E.attr(\"pane\") || $E.attr(\"resizer\")\r\n\t\t,\to = options[pane]\r\n\t\t,\ts = state[pane]\r\n\t\t;\r\n\t\tif (s.isClosed || s.isResizing)\r\n\t\t\treturn; // skip if already closed OR in process of resizing\r\n\t\telse if (o.slideTrigger_close == \"click\")\r\n\t\t\tclose_NOW(); // close immediately onClick\r\n\t\telse // trigger = mouseout - use a delay\r\n\t\t\tsetTimer(pane, \"closeSlider\", close_NOW, 300); // .3 sec delay\r\n\r\n\t\t// SUBROUTINE for timed close\r\n\t\tfunction close_NOW () {\r\n\t\t\tbindStopSlidingEvents(pane, false); // pane is being closed, so UNBIND trigger events\r\n\t\t\tif (!s.isClosed) close(pane); // skip if already closed!\r\n\t\t}\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * sizePane\r\n\t *\r\n\t * @callers  initResizable.stop()\r\n\t * @param String  pane   The pane being resized - usually west or east, but potentially north or south\r\n\t * @param Integer  newSize  The new size for this pane - will be validated\r\n\t */\r\n\tvar sizePane = function (pane, size) {\r\n\t\t// TODO: accept \"auto\" as size, and size-to-fit pane content\r\n\t\tvar \r\n\t\t\tedge\t= c[pane].edge\r\n\t\t,\tdir\t\t= c[pane].dir\r\n\t\t,\to\t\t= options[pane]\r\n\t\t,\ts\t\t= state[pane]\r\n\t\t,\t$P\t\t= $Ps[pane]\r\n\t\t,\t$R\t\t= $Rs[pane]\r\n\t\t;\r\n\t\t// calculate 'current' min/max sizes\r\n\t\tsetPaneMinMaxSizes(pane); // update pane-state\r\n\t\t// compare/update calculated min/max to user-options\r\n\t\ts.minSize = max(s.minSize, o.minSize);\r\n\t\tif (o.maxSize > 0) s.maxSize = min(s.maxSize, o.maxSize);\r\n\t\t// validate passed size\r\n\t\tsize = max(size, s.minSize);\r\n\t\tsize = min(size, s.maxSize);\r\n\t\ts.size = size; // update state\r\n\r\n\t\t// move the resizer bar and resize the pane\r\n\t\t$R.css( edge, size + cDims[edge] );\r\n\t\t$P.css( c[pane].sizeType, max(1, cssSize(pane, size)) );\r\n\r\n\t\t// resize all the adjacent panes, and adjust their toggler buttons\r\n\t\tif (!s.isSliding) sizeMidPanes(dir==\"horz\" ? \"all\" : \"center\");\r\n\t\tsizeHandles();\r\n\t\tsizeContent(pane);\r\n\t\texecUserCallback(pane, o.onresize_end || o.onresize);\r\n\t};\r\n\r\n\t/**\r\n\t * sizeMidPanes\r\n\t *\r\n\t * @callers  create(), open(), close(), onWindowResize()\r\n\t */\r\n\tvar sizeMidPanes = function (panes, overrideDims, onInit) {\r\n\t\tif (!panes || panes == \"all\") panes = \"east,west,center\";\r\n\r\n\t\tvar d = getPaneDims();\r\n\t\tif (overrideDims) $.extend( d, overrideDims );\r\n\r\n\t\t$.each(panes.split(\",\"), function() {\r\n\t\t\tif (!$Ps[this]) return; // NO PANE - skip\r\n\t\t\tvar \r\n\t\t\t\tpane\t= str(this)\r\n\t\t\t,\to\t\t= options[pane]\r\n\t\t\t,\ts\t\t= state[pane]\r\n\t\t\t,\t$P\t\t= $Ps[pane]\r\n\t\t\t,\t$R\t\t= $Rs[pane]\r\n\t\t\t,\thasRoom\t= true\r\n\t\t\t,\tCSS\t\t= {}\r\n\t\t\t;\r\n\r\n\t\t\tif (pane == \"center\") {\r\n\t\t\t\td = getPaneDims(); // REFRESH Dims because may have just 'unhidden' East or West pane after a 'resize'\r\n\t\t\t\tCSS = $.extend( {}, d ); // COPY ALL of the paneDims\r\n\t\t\t\tCSS.width  = max(1, cssW(pane, CSS.width));\r\n\t\t\t\tCSS.height = max(1, cssH(pane, CSS.height));\r\n\t\t\t\thasRoom = (CSS.width > 1 && CSS.height > 1);\r\n\t\t\t\t/*\r\n\t\t\t\t * Extra CSS for IE6 or IE7 in Quirks-mode - add 'width' to NORTH/SOUTH panes\r\n\t\t\t\t * Normally these panes have only 'left' & 'right' positions so pane auto-sizes\r\n\t\t\t\t */\r\n\t\t\t\tif ($.browser.msie && (!$.boxModel || $.browser.version < 7)) {\r\n\t\t\t\t\tif ($Ps.north) $Ps.north.css({ width: cssW($Ps.north, cDims.innerWidth) });\r\n\t\t\t\t\tif ($Ps.south) $Ps.south.css({ width: cssW($Ps.south, cDims.innerWidth) });\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse { // for east and west, set only the height\r\n\t\t\t\tCSS.top = d.top;\r\n\t\t\t\tCSS.bottom = d.bottom;\r\n\t\t\t\tCSS.height = max(1, cssH(pane, d.height));\r\n\t\t\t\thasRoom = (CSS.height > 1);\r\n\t\t\t}\r\n\r\n\t\t\tif (hasRoom) {\r\n\t\t\t\t$P.css(CSS);\r\n\t\t\t\tif (s.noRoom) {\r\n\t\t\t\t\ts.noRoom = false;\r\n\t\t\t\t\tif (s.isHidden) return;\r\n\t\t\t\t\telse show(pane, !s.isClosed);\r\n\t\t\t\t\t/* OLD CODE - keep until sure line above works right!\r\n\t\t\t\t\tif (!s.isClosed) $P.show(); // in case was previously hidden due to NOT hasRoom\r\n\t\t\t\t\tif ($R) $R.show();\r\n\t\t\t\t\t*/\r\n\t\t\t\t}\r\n\t\t\t\tif (!onInit) {\r\n\t\t\t\t\tsizeContent(pane);\r\n\t\t\t\t\texecUserCallback(pane, o.onresize_end || o.onresize);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse if (!s.noRoom) { // no room for pane, so just hide it (if not already)\r\n\t\t\t\ts.noRoom = true; // update state\r\n\t\t\t\tif (s.isHidden) return;\r\n\t\t\t\tif (onInit) { // skip onhide callback and other logic onLoad\r\n\t\t\t\t\t$P.hide();\r\n\t\t\t\t\tif ($R) $R.hide();\r\n\t\t\t\t}\r\n\t\t\t\telse hide(pane);\r\n\t\t\t}\r\n\t\t});\r\n\t};\r\n\r\n\r\n\tvar sizeContent = function (panes) {\r\n\t\tif (!panes || panes == \"all\") panes = c.allPanes;\r\n\r\n\t\t$.each(panes.split(\",\"), function() {\r\n\t\t\tif (!$Cs[this]) return; // NO CONTENT - skip\r\n\t\t\tvar \r\n\t\t\t\tpane\t= str(this)\r\n\t\t\t,\tignore\t= options[pane].contentIgnoreSelector\r\n\t\t\t,\t$P\t\t= $Ps[pane]\r\n\t\t\t,\t$C\t\t= $Cs[pane]\r\n\t\t\t,\te_C\t\t= $C[0]\t\t// DOM element\r\n\t\t\t,\theight\t= cssH($P);\t// init to pane.innerHeight\r\n\t\t\t;\r\n\t\t\t$P.children().each(function() {\r\n\t\t\t\tif (this == e_C) return; // Content elem - skip\r\n\t\t\t\tvar $E = $(this);\r\n\t\t\t\tif (!ignore || !$E.is(ignore))\r\n\t\t\t\t\theight -= $E.outerHeight();\r\n\t\t\t});\r\n\t\t\tif (height > 0)\r\n\t\t\t\theight = cssH($C, height);\r\n\t\t\tif (height < 1)\r\n\t\t\t\t$C.hide(); // no room for content!\r\n\t\t\telse\r\n\t\t\t\t$C.css({ height: height }).show();\r\n\t\t});\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * sizeHandles\r\n\t *\r\n\t * Called every time a pane is opened, closed, or resized to slide the togglers to 'center' and adjust their length if necessary\r\n\t *\r\n\t * @callers  initHandles(), open(), close(), resizeAll()\r\n\t */\r\n\tvar sizeHandles = function (panes, onInit) {\r\n\t\tif (!panes || panes == \"all\") panes = c.borderPanes;\r\n\r\n\t\t$.each(panes.split(\",\"), function() {\r\n\t\t\tvar \r\n\t\t\t\tpane\t= str(this)\r\n\t\t\t,\to\t\t= options[pane]\r\n\t\t\t,\ts\t\t= state[pane]\r\n\t\t\t,\t$P\t\t= $Ps[pane]\r\n\t\t\t,\t$R\t\t= $Rs[pane]\r\n\t\t\t,\t$T\t\t= $Ts[pane]\r\n\t\t\t;\r\n\t\t\tif (!$P || !$R || (!o.resizable && !o.closable)) return; // skip\r\n\r\n\t\t\tvar \r\n\t\t\t\tdir\t\t\t= c[pane].dir\r\n\t\t\t,\t_state\t\t= (s.isClosed ? \"_closed\" : \"_open\")\r\n\t\t\t,\tspacing\t\t= o[\"spacing\"+ _state]\r\n\t\t\t,\ttogAlign\t= o[\"togglerAlign\"+ _state]\r\n\t\t\t,\ttogLen\t\t= o[\"togglerLength\"+ _state]\r\n\t\t\t,\tpaneLen\r\n\t\t\t,\toffset\r\n\t\t\t,\tCSS = {}\r\n\t\t\t;\r\n\t\t\tif (spacing == 0) {\r\n\t\t\t\t$R.hide();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\telse if (!s.noRoom && !s.isHidden) // skip if resizer was hidden for any reason\r\n\t\t\t\t$R.show(); // in case was previously hidden\r\n\r\n\t\t\t// Resizer Bar is ALWAYS same width/height of pane it is attached to\r\n\t\t\tif (dir == \"horz\") { // north/south\r\n\t\t\t\tpaneLen = $P.outerWidth();\r\n\t\t\t\t$R.css({\r\n\t\t\t\t\twidth:\tmax(1, cssW($R, paneLen)) // account for borders & padding\r\n\t\t\t\t,\theight:\tmax(1, cssH($R, spacing)) // ditto\r\n\t\t\t\t,\tleft:\tcssNum($P, \"left\")\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t\telse { // east/west\r\n\t\t\t\tpaneLen = $P.outerHeight();\r\n\t\t\t\t$R.css({\r\n\t\t\t\t\theight:\tmax(1, cssH($R, paneLen)) // account for borders & padding\r\n\t\t\t\t,\twidth:\tmax(1, cssW($R, spacing)) // ditto\r\n\t\t\t\t,\ttop:\tcDims.top + getPaneSize(\"north\", true)\r\n\t\t\t\t//,\ttop:\tcssNum($Ps[\"center\"], \"top\")\r\n\t\t\t\t});\r\n\t\t\t\t\r\n\t\t\t}\r\n\r\n\t\t\tif ($T) {\r\n\t\t\t\tif (togLen == 0 || (s.isSliding && o.hideTogglerOnSlide)) {\r\n\t\t\t\t\t$T.hide(); // always HIDE the toggler when 'sliding'\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\t$T.show(); // in case was previously hidden\r\n\r\n\t\t\t\tif (!(togLen > 0) || togLen == \"100%\" || togLen > paneLen) {\r\n\t\t\t\t\ttogLen = paneLen;\r\n\t\t\t\t\toffset = 0;\r\n\t\t\t\t}\r\n\t\t\t\telse { // calculate 'offset' based on options.PANE.togglerAlign_open/closed\r\n\t\t\t\t\tif (typeof togAlign == \"string\") {\r\n\t\t\t\t\t\tswitch (togAlign) {\r\n\t\t\t\t\t\t\tcase \"top\":\r\n\t\t\t\t\t\t\tcase \"left\":\toffset = 0;\r\n\t\t\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\tcase \"bottom\":\r\n\t\t\t\t\t\t\tcase \"right\":\toffset = paneLen - togLen;\r\n\t\t\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\tcase \"middle\":\r\n\t\t\t\t\t\t\tcase \"center\":\r\n\t\t\t\t\t\t\tdefault:\t\toffset = Math.floor((paneLen - togLen) / 2); // 'default' catches typos\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse { // togAlign = number\r\n\t\t\t\t\t\tvar x = parseInt(togAlign); //\r\n\t\t\t\t\t\tif (togAlign >= 0) offset = x;\r\n\t\t\t\t\t\telse offset = paneLen - togLen + x; // NOTE: x is negative!\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar\r\n\t\t\t\t\t$TC_o = (o.togglerContent_open   ? $T.children(\".content-open\") : false)\r\n\t\t\t\t,\t$TC_c = (o.togglerContent_closed ? $T.children(\".content-closed\")   : false)\r\n\t\t\t\t,\t$TC   = (s.isClosed ? $TC_c : $TC_o)\r\n\t\t\t\t;\r\n\t\t\t\tif ($TC_o) $TC_o.css(\"display\", s.isClosed ? \"none\" : \"block\");\r\n\t\t\t\tif ($TC_c) $TC_c.css(\"display\", s.isClosed ? \"block\" : \"none\");\r\n\r\n\t\t\t\tif (dir == \"horz\") { // north/south\r\n\t\t\t\t\tvar width = cssW($T, togLen);\r\n\t\t\t\t\t$T.css({\r\n\t\t\t\t\t\twidth:\tmax(0, width)  // account for borders & padding\r\n\t\t\t\t\t,\theight:\tmax(1, cssH($T, spacing)) // ditto\r\n\t\t\t\t\t,\tleft:\toffset // TODO: VERIFY that toggler  positions correctly for ALL values\r\n\t\t\t\t\t});\r\n\t\t\t\t\tif ($TC) // CENTER the toggler content SPAN\r\n\t\t\t\t\t\t$TC.css(\"marginLeft\", Math.floor((width-$TC.outerWidth())/2)); // could be negative\r\n\t\t\t\t}\r\n\t\t\t\telse { // east/west\r\n\t\t\t\t\tvar height = cssH($T, togLen);\r\n\t\t\t\t\t$T.css({\r\n\t\t\t\t\t\theight:\tmax(0, height)  // account for borders & padding\r\n\t\t\t\t\t,\twidth:\tmax(1, cssW($T, spacing)) // ditto\r\n\t\t\t\t\t,\ttop:\toffset // POSITION the toggler\r\n\t\t\t\t\t});\r\n\t\t\t\t\tif ($TC) // CENTER the toggler content SPAN\r\n\t\t\t\t\t\t$TC.css(\"marginTop\", Math.floor((height-$TC.outerHeight())/2)); // could be negative\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// DONE measuring and sizing this resizer/toggler, so can be 'hidden' now\r\n\t\t\tif (onInit && o.initHidden) {\r\n\t\t\t\t$R.hide();\r\n\t\t\t\tif ($T) $T.hide();\r\n\t\t\t}\r\n\t\t});\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * resizeAll\r\n\t *\r\n\t * @callers  window.onresize(), callbacks or custom code\r\n\t */\r\n\tvar resizeAll = function () {\r\n\t\tvar\r\n\t\t\toldW\t= cDims.innerWidth\r\n\t\t,\toldH\t= cDims.innerHeight\r\n\t\t;\r\n\t\tcDims = state.container = getElemDims($Container); // UPDATE container dimensions\r\n\r\n\t\tvar\r\n\t\t\tcheckH\t= (cDims.innerHeight < oldH)\r\n\t\t,\tcheckW\t= (cDims.innerWidth < oldW)\r\n\t\t,\ts, dir\r\n\t\t;\r\n\r\n\t\tif (checkH || checkW)\r\n\t\t\t// NOTE special order for sizing: S-N-E-W\r\n\t\t\t$.each([\"south\",\"north\",\"east\",\"west\"], function(i,pane) {\r\n\t\t\t\ts = state[pane];\r\n\t\t\t\tdir = c[pane].dir;\r\n\t\t\t\tif (!s.isClosed && ((checkH && dir==\"horz\") || (checkW && dir==\"vert\"))) {\r\n\t\t\t\t\tsetPaneMinMaxSizes(pane); // update pane-state\r\n\t\t\t\t\t// shrink pane if 'too big' to fit\r\n\t\t\t\t\tif (s.size > s.maxSize)\r\n\t\t\t\t\t\tsizePane(pane, s.maxSize);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\tsizeMidPanes(\"all\");\r\n\t\tsizeHandles(\"all\"); // reposition the toggler elements\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * keyDown\r\n\t *\r\n\t * Capture keys when enableCursorHotkey - toggle pane if hotkey pressed\r\n\t *\r\n\t * @callers  document.keydown()\r\n\t */\r\n\tfunction keyDown (evt) {\r\n\t\tif (!evt) return true;\r\n\t\tvar code = evt.keyCode;\r\n\t\tif (code < 33) return true; // ignore special keys: ENTER, TAB, etc\r\n\r\n\t\tvar\r\n\t\t\tPANE = {\r\n\t\t\t\t38: \"north\" // Up Cursor\r\n\t\t\t,\t40: \"south\" // Down Cursor\r\n\t\t\t,\t37: \"west\"  // Left Cursor\r\n\t\t\t,\t39: \"east\"  // Right Cursor\r\n\t\t\t}\r\n\t\t,\tisCursorKey = (code >= 37 && code <= 40)\r\n\t\t,\tALT = evt.altKey // no worky!\r\n\t\t,\tSHIFT = evt.shiftKey\r\n\t\t,\tCTRL = evt.ctrlKey\r\n\t\t,\tpane = false\r\n\t\t,\ts, o, k, m, el\r\n\t\t;\r\n\r\n\t\tif (!CTRL && !SHIFT)\r\n\t\t\treturn true; // no modifier key - abort\r\n\t\telse if (isCursorKey && options[PANE[code]].enableCursorHotkey) // valid cursor-hotkey\r\n\t\t\tpane = PANE[code];\r\n\t\telse // check to see if this matches a custom-hotkey\r\n\t\t\t$.each(c.borderPanes.split(\",\"), function(i,p) { // loop each pane to check its hotkey\r\n\t\t\t\to = options[p];\r\n\t\t\t\tk = o.customHotkey;\r\n\t\t\t\tm = o.customHotkeyModifier; // if missing or invalid, treated as \"CTRL+SHIFT\"\r\n\t\t\t\tif ((SHIFT && m==\"SHIFT\") || (CTRL && m==\"CTRL\") || (CTRL && SHIFT)) { // Modifier matches\r\n\t\t\t\t\tif (k && code == (isNaN(k) || k <= 9 ? k.toUpperCase().charCodeAt(0) : k)) { // Key matches\r\n\t\t\t\t\t\tpane = p;\r\n\t\t\t\t\t\treturn false; // BREAK\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\tif (!pane) return true; // no hotkey - abort\r\n\r\n\t\t// validate pane\r\n\t\to = options[pane]; // get pane options\r\n\t\ts = state[pane]; // get pane options\r\n\t\tif (!o.enableCursorHotkey || s.isHidden || !$Ps[pane]) return true;\r\n\r\n\t\t// see if user is in a 'form field' because may be 'selecting text'!\r\n\t\tel = evt.target || evt.srcElement;\r\n\t\tif (el && SHIFT && isCursorKey && (el.tagName==\"TEXTAREA\" || (el.tagName==\"INPUT\" && (code==37 || code==39))))\r\n\t\t\treturn true; // allow text-selection\r\n\r\n\t\t// SYNTAX NOTES\r\n\t\t// use \"returnValue=false\" to abort keystroke but NOT abort function - can run another command afterwards\r\n\t\t// use \"return false\" to abort keystroke AND abort function\r\n\t\ttoggle(pane);\r\n\t\tevt.stopPropagation();\r\n\t\tevt.returnValue = false; // CANCEL key\r\n\t\treturn false;\r\n\t};\r\n\r\n\r\n/*\r\n * ###########################\r\n *     UTILITY METHODS\r\n *   called externally only\r\n * ###########################\r\n */\r\n\r\n\tfunction allowOverflow (elem) {\r\n\t\tif (this && this.tagName) elem = this; // BOUND to element\r\n\t\tvar $P;\r\n\t\tif (typeof elem==\"string\")\r\n\t\t\t$P = $Ps[elem];\r\n\t\telse {\r\n\t\t\tif ($(elem).attr(\"pane\")) $P = $(elem);\r\n\t\t\telse $P = $(elem).parents(\"div[pane]:first\");\r\n\t\t}\r\n\t\tif (!$P.length) return; // INVALID\r\n\r\n\t\tvar\r\n\t\t\tpane\t= $P.attr(\"pane\")\r\n\t\t,\ts\t\t= state[pane]\r\n\t\t;\r\n\r\n\t\t// if pane is already raised, then reset it before doing it again!\r\n\t\t// this would happen if allowOverflow is attached to BOTH the pane and an element \r\n\t\tif (s.cssSaved)\r\n\t\t\tresetOverflow(pane); // reset previous CSS before continuing\r\n\r\n\t\t// if pane is raised by sliding or resizing, or it's closed, then abort\r\n\t\tif (s.isSliding || s.isResizing || s.isClosed) {\r\n\t\t\ts.cssSaved = false;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar\r\n\t\t\tnewCSS\t= { zIndex: (c.zIndex.pane_normal + 1) }\r\n\t\t,\tcurCSS\t= {}\r\n\t\t,\tof\t\t= $P.css(\"overflow\")\r\n\t\t,\tofX\t\t= $P.css(\"overflowX\")\r\n\t\t,\tofY\t\t= $P.css(\"overflowY\")\r\n\t\t;\r\n\t\t// determine which, if any, overflow settings need to be changed\r\n\t\tif (of != \"visible\") {\r\n\t\t\tcurCSS.overflow = of;\r\n\t\t\tnewCSS.overflow = \"visible\";\r\n\t\t}\r\n\t\tif (ofX && ofX != \"visible\" && ofX != \"auto\") {\r\n\t\t\tcurCSS.overflowX = ofX;\r\n\t\t\tnewCSS.overflowX = \"visible\";\r\n\t\t}\r\n\t\tif (ofY && ofY != \"visible\" && ofY != \"auto\") {\r\n\t\t\tcurCSS.overflowY = ofX;\r\n\t\t\tnewCSS.overflowY = \"visible\";\r\n\t\t}\r\n\r\n\t\t// save the current overflow settings - even if blank!\r\n\t\ts.cssSaved = curCSS;\r\n\r\n\t\t// apply new CSS to raise zIndex and, if necessary, make overflow 'visible'\r\n\t\t$P.css( newCSS );\r\n\r\n\t\t// make sure the zIndex of all other panes is normal\r\n\t\t$.each(c.allPanes.split(\",\"), function(i, p) {\r\n\t\t\tif (p != pane) resetOverflow(p);\r\n\t\t});\r\n\r\n\t};\r\n\r\n\tfunction resetOverflow (elem) {\r\n\t\tif (this && this.tagName) elem = this; // BOUND to element\r\n\t\tvar $P;\r\n\t\tif (typeof elem==\"string\")\r\n\t\t\t$P = $Ps[elem];\r\n\t\telse {\r\n\t\t\tif ($(elem).hasClass(\"ui-layout-pane\")) $P = $(elem);\r\n\t\t\telse $P = $(elem).parents(\"div[pane]:first\");\r\n\t\t}\r\n\t\tif (!$P.length) return; // INVALID\r\n\r\n\t\tvar\r\n\t\t\tpane\t= $P.attr(\"pane\")\r\n\t\t,\ts\t\t= state[pane]\r\n\t\t,\tCSS\t\t= s.cssSaved || {}\r\n\t\t;\r\n\t\t// reset the zIndex\r\n\t\tif (!s.isSliding && !s.isResizing)\r\n\t\t\t$P.css(\"zIndex\", c.zIndex.pane_normal);\r\n\r\n\t\t// reset Overflow - if necessary\r\n\t\t$P.css( CSS );\r\n\r\n\t\t// clear var\r\n\t\ts.cssSaved = false;\r\n\t};\r\n\r\n\r\n\t/**\r\n\t* getBtn\r\n\t*\r\n\t* Helper function to validate params received by addButton utilities\r\n\t*\r\n\t* @param String   selector \tjQuery selector for button, eg: \".ui-layout-north .toggle-button\"\r\n\t* @param String   pane \t\tName of the pane the button is for: 'north', 'south', etc.\r\n\t* @returns  If both params valid, the element matching 'selector' in a jQuery wrapper - otherwise 'false'\r\n\t*/\r\n\tfunction getBtn(selector, pane, action) {\r\n\t\tvar\r\n\t\t\t$E = $(selector)\r\n\t\t,\terr = \"Error Adding Button \\n\\nInvalid \"\r\n\t\t;\r\n\t\tif (!$E.length) // element not found\r\n\t\t\talert(err+\"selector: \"+ selector);\r\n\t\telse if (c.borderPanes.indexOf(pane) == -1) // invalid 'pane' sepecified\r\n\t\t\talert(err+\"pane: \"+ pane);\r\n\t\telse { // VALID\r\n\t\t\tvar btn = options[pane].buttonClass +\"-\"+ action;\r\n\t\t\t$E.addClass( btn +\" \"+ btn +\"-\"+ pane );\r\n\t\t\treturn $E;\r\n\t\t}\r\n\t\treturn false;  // INVALID\r\n\t};\r\n\r\n\r\n\t/**\r\n\t* addToggleBtn\r\n\t*\r\n\t* Add a custom Toggler button for a pane\r\n\t*\r\n\t* @param String   selector \tjQuery selector for button, eg: \".ui-layout-north .toggle-button\"\r\n\t* @param String   pane \t\tName of the pane the button is for: 'north', 'south', etc.\r\n\t*/\r\n\tfunction addToggleBtn (selector, pane) {\r\n\t\tvar $E = getBtn(selector, pane, \"toggle\");\r\n\t\tif ($E)\r\n\t\t\t$E\r\n\t\t\t\t.attr(\"title\", state[pane].isClosed ? \"Open\" : \"Close\")\r\n\t\t\t\t.click(function (evt) {\r\n\t\t\t\t\ttoggle(pane);\r\n\t\t\t\t\tevt.stopPropagation();\r\n\t\t\t\t})\r\n\t\t\t;\r\n\t};\r\n\r\n\t/**\r\n\t* addOpenBtn\r\n\t*\r\n\t* Add a custom Open button for a pane\r\n\t*\r\n\t* @param String   selector \tjQuery selector for button, eg: \".ui-layout-north .open-button\"\r\n\t* @param String   pane \t\tName of the pane the button is for: 'north', 'south', etc.\r\n\t*/\r\n\tfunction addOpenBtn (selector, pane) {\r\n\t\tvar $E = getBtn(selector, pane, \"open\");\r\n\t\tif ($E)\r\n\t\t\t$E\r\n\t\t\t\t.attr(\"title\", \"Open\")\r\n\t\t\t\t.click(function (evt) {\r\n\t\t\t\t\topen(pane);\r\n\t\t\t\t\tevt.stopPropagation();\r\n\t\t\t\t})\r\n\t\t\t;\r\n\t};\r\n\r\n\t/**\r\n\t* addCloseBtn\r\n\t*\r\n\t* Add a custom Close button for a pane\r\n\t*\r\n\t* @param String   selector \tjQuery selector for button, eg: \".ui-layout-north .close-button\"\r\n\t* @param String   pane \t\tName of the pane the button is for: 'north', 'south', etc.\r\n\t*/\r\n\tfunction addCloseBtn (selector, pane) {\r\n\t\tvar $E = getBtn(selector, pane, \"close\");\r\n\t\tif ($E)\r\n\t\t\t$E\r\n\t\t\t\t.attr(\"title\", \"Close\")\r\n\t\t\t\t.click(function (evt) {\r\n\t\t\t\t\tclose(pane);\r\n\t\t\t\t\tevt.stopPropagation();\r\n\t\t\t\t})\r\n\t\t\t;\r\n\t};\r\n\r\n\t/**\r\n\t* addPinBtn\r\n\t*\r\n\t* Add a custom Pin button for a pane\r\n\t*\r\n\t* Four classes are added to the element, based on the paneClass for the associated pane...\r\n\t* Assuming the default paneClass and the pin is 'up', these classes are added for a west-pane pin:\r\n\t*  - ui-layout-pane-pin\r\n\t*  - ui-layout-pane-west-pin\r\n\t*  - ui-layout-pane-pin-up\r\n\t*  - ui-layout-pane-west-pin-up\r\n\t*\r\n\t* @param String   selector \tjQuery selector for button, eg: \".ui-layout-north .ui-layout-pin\"\r\n\t* @param String   pane \t\tName of the pane the pin is for: 'north', 'south', etc.\r\n\t*/\r\n\tfunction addPinBtn (selector, pane) {\r\n\t\tvar $E = getBtn(selector, pane, \"pin\");\r\n\t\tif ($E) {\r\n\t\t\tvar s = state[pane];\r\n\t\t\t$E.click(function (evt) {\r\n\t\t\t\tsetPinState($(this), pane, (s.isSliding || s.isClosed));\r\n\t\t\t\tif (s.isSliding || s.isClosed) open( pane ); // change from sliding to open\r\n\t\t\t\telse close( pane ); // slide-closed\r\n\t\t\t\tevt.stopPropagation();\r\n\t\t\t});\r\n\t\t\t// add up/down pin attributes and classes\r\n\t\t\tsetPinState ($E, pane, (!s.isClosed && !s.isSliding));\r\n\t\t\t// add this pin to the pane data so we can 'sync it' automatically\r\n\t\t\t// PANE.pins key is an array so we can store multiple pins for each pane\r\n\t\t\tc[pane].pins.push( selector ); // just save the selector string\r\n\t\t}\r\n\t};\r\n\r\n\t/**\r\n\t* syncPinBtns\r\n\t*\r\n\t* INTERNAL function to sync 'pin buttons' when pane is opened or closed\r\n\t* Unpinned means the pane is 'sliding' - ie, over-top of the adjacent panes\r\n\t*\r\n\t* @callers  open(), close()\r\n\t* @params  pane   These are the params returned to callbacks by layout()\r\n\t* @params  doPin  True means set the pin 'down', False means 'up'\r\n\t*/\r\n\tfunction syncPinBtns (pane, doPin) {\r\n\t\t$.each(c[pane].pins, function (i, selector) {\r\n\t\t\tsetPinState($(selector), pane, doPin);\r\n\t\t});\r\n\t};\r\n\r\n\t/**\r\n\t* setPinState\r\n\t*\r\n\t* Change the class of the pin button to make it look 'up' or 'down'\r\n\t*\r\n\t* @callers  addPinBtn(), syncPinBtns()\r\n\t* @param Element  $Pin\t\tThe pin-span element in a jQuery wrapper\r\n\t* @param Boolean  doPin\t\tTrue = set the pin 'down', False = set it 'up'\r\n\t* @param String   pinClass\tThe root classname for pins - will add '-up' or '-down' suffix\r\n\t*/\r\n\tfunction setPinState ($Pin, pane, doPin) {\r\n\t\tvar updown = $Pin.attr(\"pin\");\r\n\t\tif (updown && doPin == (updown==\"down\")) return; // already in correct state\r\n\t\tvar\r\n\t\t\troot\t= options[pane].buttonClass\r\n\t\t,\tclass1\t= root +\"-pin\"\r\n\t\t,\tclass2\t= class1 +\"-\"+ pane\r\n\t\t,\tUP1\t\t= class1 + \"-up\"\r\n\t\t,\tUP2\t\t= class2 + \"-up\"\r\n\t\t,\tDN1\t\t= class1 + \"-down\"\r\n\t\t,\tDN2\t\t= class2 + \"-down\"\r\n\t\t;\r\n\t\t$Pin\r\n\t\t\t.attr(\"pin\", doPin ? \"down\" : \"up\") // logic\r\n\t\t\t.attr(\"title\", doPin ? \"Un-Pin\" : \"Pin\")\r\n\t\t\t.removeClass( doPin ? UP1 : DN1 ) \r\n\t\t\t.removeClass( doPin ? UP2 : DN2 ) \r\n\t\t\t.addClass( doPin ? DN1 : UP1 ) \r\n\t\t\t.addClass( doPin ? DN2 : UP2 ) \r\n\t\t;\r\n\t};\r\n\r\n\r\n/*\r\n * ###########################\r\n * CREATE/RETURN BORDER-LAYOUT\r\n * ###########################\r\n */\r\n\r\n\t// init global vars\r\n\tvar \r\n\t\t$Container = $(this).css({ overflow: \"hidden\" }) // Container elem\r\n\t,\t$Ps\t\t= {} // Panes x4\t- set in initPanes()\r\n\t,\t$Cs\t\t= {} // Content x4\t- set in initPanes()\r\n\t,\t$Rs\t\t= {} // Resizers x4\t- set in initHandles()\r\n\t,\t$Ts\t\t= {} // Togglers x4\t- set in initHandles()\r\n\t//\tobject aliases\r\n\t,\tc\t\t= config // alias for config hash\r\n\t,\tcDims\t= state.container // alias for easy access to 'container dimensions'\r\n\t;\r\n\r\n\t// create the border layout NOW\r\n\tcreate();\r\n\r\n\t// return object pointers to expose data & option Properties, and primary action Methods\r\n\treturn {\r\n\t\toptions:\t\toptions\t\t\t// property - options hash\r\n\t,\tstate:\t\t\tstate\t\t\t// property - dimensions hash\r\n\t,\tpanes:\t\t\t$Ps\t\t\t\t// property - object pointers for ALL panes: panes.north, panes.center\r\n\t,\ttoggle:\t\t\ttoggle\t\t\t// method - pass a 'pane' (\"north\", \"west\", etc)\r\n\t,\topen:\t\t\topen\t\t\t// method - ditto\r\n\t,\tclose:\t\t\tclose\t\t\t// method - ditto\r\n\t,\thide:\t\t\thide\t\t\t// method - ditto\r\n\t,\tshow:\t\t\tshow\t\t\t// method - ditto\r\n\t,\tresizeContent:\tsizeContent\t\t// method - ditto\r\n\t,\tsizePane:\t\tsizePane\t\t// method - pass a 'pane' AND a 'size' in pixels\r\n\t,\tresizeAll:\t\tresizeAll\t\t// method - no parameters\r\n\t,\taddToggleBtn:\taddToggleBtn\t// utility - pass element selector and 'pane'\r\n\t,\taddOpenBtn:\t\taddOpenBtn\t\t// utility - ditto\r\n\t,\taddCloseBtn:\taddCloseBtn\t\t// utility - ditto\r\n\t,\taddPinBtn:\t\taddPinBtn\t\t// utility - ditto\r\n\t,\tallowOverflow:\tallowOverflow\t// utility - pass calling element\r\n\t,\tresetOverflow:\tresetOverflow\t// utility - ditto\r\n\t,\tcssWidth:\t\tcssW\r\n\t,\tcssHeight:\t\tcssH\r\n\t};\r\n\r\n}\r\n})( jQuery );"
  },
  {
    "path": "src/lib/jquery.tablednd_0_5.js",
    "content": "/**\n * TableDnD plug-in for JQuery, allows you to drag and drop table rows\n * You can set up various options to control how the system will work\n * Copyright (c) Denis Howlett <denish@isocra.com>\n * Licensed like jQuery, see http://docs.jquery.com/License.\n *\n * Configuration options:\n * \n * onDragStyle\n *     This is the style that is assigned to the row during drag. There are limitations to the styles that can be\n *     associated with a row (such as you can't assign a border--well you can, but it won't be\n *     displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as\n *     a map (as used in the jQuery css(...) function).\n * onDropStyle\n *     This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations\n *     to what you can do. Also this replaces the original style, so again consider using onDragClass which\n *     is simply added and then removed on drop.\n * onDragClass\n *     This class is added for the duration of the drag and then removed when the row is dropped. It is more\n *     flexible than using onDragStyle since it can be inherited by the row cells and other content. The default\n *     is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your\n *     stylesheet.\n * onDrop\n *     Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table\n *     and the row that was dropped. You can work out the new order of the rows by using\n *     table.rows.\n * onDragStart\n *     Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the\n *     table and the row which the user has started to drag.\n * onAllowDrop\n *     Pass a function that will be called as a row is over another row. If the function returns true, allow \n *     dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under\n *     the cursor. It returns a boolean: true allows the drop, false doesn't allow it.\n * scrollAmount\n *     This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the\n *     window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2,\n *     FF3 beta\n * dragHandle\n *     This is the name of a class that you assign to one or more cells in each row that is draggable. If you\n *     specify this class, then you are responsible for setting cursor: move in the CSS and only these cells\n *     will have the drag behaviour. If you do not specify a dragHandle, then you get the old behaviour where\n *     the whole row is draggable.\n * \n * Other ways to control behaviour:\n *\n * Add class=\"nodrop\" to any rows for which you don't want to allow dropping, and class=\"nodrag\" to any rows\n * that you don't want to be draggable.\n *\n * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form\n * <tableID>[]=<rowID1>&<tableID>[]=<rowID2> so that you can send this back to the server. The table must have\n * an ID as must all the rows.\n *\n * Other methods:\n *\n * $(\"...\").tableDnDUpdate() \n * Will update all the matching tables, that is it will reapply the mousedown method to the rows (or handle cells).\n * This is useful if you have updated the table rows using Ajax and you want to make the table draggable again.\n * The table maintains the original configuration (so you don't have to specify it again).\n *\n * $(\"...\").tableDnDSerialize()\n * Will serialize and return the serialized string as above, but for each of the matching tables--so it can be\n * called from anywhere and isn't dependent on the currentTable being set up correctly before calling\n *\n * Known problems:\n * - Auto-scoll has some problems with IE7  (it scrolls even when it shouldn't), work-around: set scrollAmount to 0\n * \n * Version 0.2: 2008-02-20 First public version\n * Version 0.3: 2008-02-07 Added onDragStart option\n *                         Made the scroll amount configurable (default is 5 as before)\n * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes\n *                         Added onAllowDrop to control dropping\n *                         Fixed a bug which meant that you couldn't set the scroll amount in both directions\n *                         Added serialize method\n * Version 0.5: 2008-05-16 Changed so that if you specify a dragHandle class it doesn't make the whole row\n *                         draggable\n *                         Improved the serialize method to use a default (and settable) regular expression.\n *                         Added tableDnDupate() and tableDnDSerialize() to be called when you are outside the table\n */\njQuery.tableDnD = {\n    /** Keep hold of the current table being dragged */\n    currentTable : null,\n    /** Keep hold of the current drag object if any */\n    dragObject: null,\n    /** The current mouse offset */\n    mouseOffset: null,\n    /** Remember the old value of Y so that we don't do too much processing */\n    oldY: 0,\n\n    /** Actually build the structure */\n    build: function(options) {\n        // Set up the defaults if any\n\n        this.each(function() {\n            // This is bound to each matching table, set up the defaults and override with user options\n            this.tableDnDConfig = jQuery.extend({\n                onDragStyle: null,\n                onDropStyle: null,\n\t\t\t\t// Add in the default class for whileDragging\n\t\t\t\tonDragClass: \"tDnD_whileDrag\",\n                onDrop: null,\n                onDragStart: null,\n                scrollAmount: 5,\n\t\t\t\tserializeRegexp: /[^\\-]*$/, // The regular expression to use to trim row IDs\n\t\t\t\tserializeParamName: null, // If you want to specify another parameter name instead of the table ID\n                dragHandle: null // If you give the name of a class here, then only Cells with this class will be draggable\n            }, options || {});\n            // Now make the rows draggable\n            jQuery.tableDnD.makeDraggable(this);\n        });\n\n        // Now we need to capture the mouse up and mouse move event\n        // We can use bind so that we don't interfere with other event handlers\n        jQuery(document)\n            .bind('mousemove', jQuery.tableDnD.mousemove)\n            .bind('mouseup', jQuery.tableDnD.mouseup);\n\n        // Don't break the chain\n        return this;\n    },\n\n    /** This function makes all the rows on the table draggable apart from those marked as \"NoDrag\" */\n    makeDraggable: function(table) {\n        var config = table.tableDnDConfig;\n\t\tif (table.tableDnDConfig.dragHandle) {\n\t\t\t// We only need to add the event to the specified cells\n\t\t\tvar cells = jQuery(\"td.\"+table.tableDnDConfig.dragHandle, table);\n\t\t\tcells.each(function() {\n\t\t\t\t// The cell is bound to \"this\"\n                jQuery(this).mousedown(function(ev) {\n                    jQuery.tableDnD.dragObject = this.parentNode;\n                    jQuery.tableDnD.currentTable = table;\n                    jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev);\n                    if (config.onDragStart) {\n                        // Call the onDrop method if there is one\n                        config.onDragStart(table, this);\n                    }\n                    return false;\n                });\n\t\t\t})\n\t\t} else {\n\t\t\t// For backwards compatibility, we add the event to the whole row\n\t        var rows = jQuery(\"tr\", table); // get all the rows as a wrapped set\n\t        rows.each(function() {\n\t\t\t\t// Iterate through each row, the row is bound to \"this\"\n\t\t\t\tvar row = jQuery(this);\n\t\t\t\tif (! row.hasClass(\"nodrag\")) {\n\t                row.mousedown(function(ev) {\n\t                    if (ev.target.tagName == \"TD\") {\n\t                        jQuery.tableDnD.dragObject = this;\n\t                        jQuery.tableDnD.currentTable = table;\n\t                        jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev);\n\t                        if (config.onDragStart) {\n\t                            // Call the onDrop method if there is one\n\t                            config.onDragStart(table, this);\n\t                        }\n\t                        return false;\n\t                    }\n\t                }).css(\"cursor\", \"move\"); // Store the tableDnD object\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t},\n\n\tupdateTables: function() {\n\t\tthis.each(function() {\n\t\t\t// this is now bound to each matching table\n\t\t\tif (this.tableDnDConfig) {\n\t\t\t\tjQuery.tableDnD.makeDraggable(this);\n\t\t\t}\n\t\t})\n\t},\n\n    /** Get the mouse coordinates from the event (allowing for browser differences) */\n    mouseCoords: function(ev){\n        if(ev.pageX || ev.pageY){\n            return {x:ev.pageX, y:ev.pageY};\n        }\n        return {\n            x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,\n            y:ev.clientY + document.body.scrollTop  - document.body.clientTop\n        };\n    },\n\n    /** Given a target element and a mouse event, get the mouse offset from that element.\n        To do this we need the element's position and the mouse position */\n    getMouseOffset: function(target, ev) {\n        ev = ev || window.event;\n\n        var docPos    = this.getPosition(target);\n        var mousePos  = this.mouseCoords(ev);\n        return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};\n    },\n\n    /** Get the position of an element by going up the DOM tree and adding up all the offsets */\n    getPosition: function(e){\n        var left = 0;\n        var top  = 0;\n        /** Safari fix -- thanks to Luis Chato for this! */\n        if (e.offsetHeight == 0) {\n            /** Safari 2 doesn't correctly grab the offsetTop of a table row\n            this is detailed here:\n            http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/\n            the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild.\n            note that firefox will return a text node as a first child, so designing a more thorough\n            solution may need to take that into account, for now this seems to work in firefox, safari, ie */\n            e = e.firstChild; // a table cell\n        }\n\n        while (e.offsetParent){\n            left += e.offsetLeft;\n            top  += e.offsetTop;\n            e     = e.offsetParent;\n        }\n\n        left += e.offsetLeft;\n        top  += e.offsetTop;\n\n        return {x:left, y:top};\n    },\n\n    mousemove: function(ev) {\n        if (jQuery.tableDnD.dragObject == null) {\n            return;\n        }\n\n        var dragObj = jQuery(jQuery.tableDnD.dragObject);\n        var config = jQuery.tableDnD.currentTable.tableDnDConfig;\n        var mousePos = jQuery.tableDnD.mouseCoords(ev);\n        var y = mousePos.y - jQuery.tableDnD.mouseOffset.y;\n        //auto scroll the window\n\t    var yOffset = window.pageYOffset;\n\t \tif (document.all) {\n\t        // Windows version\n\t        //yOffset=document.body.scrollTop;\n\t        if (typeof document.compatMode != 'undefined' &&\n\t             document.compatMode != 'BackCompat') {\n\t           yOffset = document.documentElement.scrollTop;\n\t        }\n\t        else if (typeof document.body != 'undefined') {\n\t           yOffset=document.body.scrollTop;\n\t        }\n\n\t    }\n\t\t    \n\t\tif (mousePos.y-yOffset < config.scrollAmount) {\n\t    \twindow.scrollBy(0, -config.scrollAmount);\n\t    } else {\n            var windowHeight = window.innerHeight ? window.innerHeight\n                    : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;\n            if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) {\n                window.scrollBy(0, config.scrollAmount);\n            }\n        }\n\n\n        if (y != jQuery.tableDnD.oldY) {\n            // work out if we're going up or down...\n            var movingDown = y > jQuery.tableDnD.oldY;\n            // update the old value\n            jQuery.tableDnD.oldY = y;\n            // update the style to show we're dragging\n\t\t\tif (config.onDragClass) {\n\t\t\t\tdragObj.addClass(config.onDragClass);\n\t\t\t} else {\n\t            dragObj.css(config.onDragStyle);\n\t\t\t}\n            // If we're over a row then move the dragged row to there so that the user sees the\n            // effect dynamically\n            var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y);\n            if (currentRow) {\n                // TODO worry about what happens when there are multiple TBODIES\n                if (movingDown && jQuery.tableDnD.dragObject != currentRow) {\n                    jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling);\n                } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) {\n                    jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow);\n                }\n            }\n        }\n\n        return false;\n    },\n\n    /** We're only worried about the y position really, because we can only move rows up and down */\n    findDropTargetRow: function(draggedRow, y) {\n        var rows = jQuery.tableDnD.currentTable.rows;\n        for (var i=0; i<rows.length; i++) {\n            var row = rows[i];\n            var rowY    = this.getPosition(row).y;\n            var rowHeight = parseInt(row.offsetHeight)/2;\n            if (row.offsetHeight == 0) {\n                rowY = this.getPosition(row.firstChild).y;\n                rowHeight = parseInt(row.firstChild.offsetHeight)/2;\n            }\n            // Because we always have to insert before, we need to offset the height a bit\n            if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) {\n                // that's the row we're over\n\t\t\t\t// If it's the same as the current row, ignore it\n\t\t\t\tif (row == draggedRow) {return null;}\n                var config = jQuery.tableDnD.currentTable.tableDnDConfig;\n                if (config.onAllowDrop) {\n                    if (config.onAllowDrop(draggedRow, row)) {\n                        return row;\n                    } else {\n                        return null;\n                    }\n                } else {\n\t\t\t\t\t// If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic)\n                    var nodrop = jQuery(row).hasClass(\"nodrop\");\n                    if (! nodrop) {\n                        return row;\n                    } else {\n                        return null;\n                    }\n                }\n                return row;\n            }\n        }\n        return null;\n    },\n\n    mouseup: function(e) {\n        if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) {\n            var droppedRow = jQuery.tableDnD.dragObject;\n            var config = jQuery.tableDnD.currentTable.tableDnDConfig;\n            // If we have a dragObject, then we need to release it,\n            // The row will already have been moved to the right place so we just reset stuff\n\t\t\tif (config.onDragClass) {\n\t            jQuery(droppedRow).removeClass(config.onDragClass);\n\t\t\t} else {\n\t            jQuery(droppedRow).css(config.onDropStyle);\n\t\t\t}\n            jQuery.tableDnD.dragObject   = null;\n            if (config.onDrop) {\n                // Call the onDrop method if there is one\n                config.onDrop(jQuery.tableDnD.currentTable, droppedRow);\n            }\n            jQuery.tableDnD.currentTable = null; // let go of the table too\n        }\n    },\n\n    serialize: function() {\n        if (jQuery.tableDnD.currentTable) {\n            return jQuery.tableDnD.serializeTable(jQuery.tableDnD.currentTable);\n        } else {\n            return \"Error: No Table id set, you need to set an id on your table and every row\";\n        }\n    },\n\n\tserializeTable: function(table) {\n        var result = \"\";\n        var tableId = table.id;\n        var rows = table.rows;\n        for (var i=0; i<rows.length; i++) {\n            if (result.length > 0) result += \"&\";\n            var rowId = rows[i].id;\n            if (rowId && rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) {\n                rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0];\n            }\n\n            result += tableId + '[]=' + rowId;\n        }\n        return result;\n\t},\n\n\tserializeTables: function() {\n        var result = \"\";\n        this.each(function() {\n\t\t\t// this is now bound to each matching table\n\t\t\tresult += jQuery.tableDnD.serializeTable(this);\n\t\t});\n        return result;\n    }\n\n}\n\njQuery.fn.extend(\n\t{\n\t\ttableDnD : jQuery.tableDnD.build,\n\t\ttableDnDUpdate : jQuery.tableDnD.updateTables,\n\t\ttableDnDSerialize: jQuery.tableDnD.serializeTables\n\t}\n);"
  },
  {
    "path": "src/license.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Scraper License</title>\n    <style type=\"text/css\" media=\"screen\">\n      body {width: 700px; margin: 0 auto;}\n    </style>\n  </head>\n  <body>\n    <pre>\nCopyright (c) 2010, David Heaton\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n\n     * Neither the name of bit155 nor the names of its contributors\n       may be used to endorse or promote products derived from this software\n       without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.      \n    </pre>\n  </body>\n</html>\n"
  },
  {
    "path": "src/manifest.json",
    "content": "{\n  \"name\": \"Scraper\",\n  \"version\": \"1.6\",\n  \"description\": \"Scraper is a Google Chrome extension for getting data out of web pages and into spreadsheets.\",\n  \"icons\": {\n    \"16\": \"img/scraper16.png\",\n    \"32\": \"img/scraper32.png\",\n    \"48\": \"img/scraper48.png\",\n    \"128\": \"img/scraper128.png\"\n  },\n  \"background_page\": \"background.html\",\n\t\"permissions\": [ \"tabs\", \"contextMenus\", \"http://*/*\", \"https://*/*\", \"unlimitedStorage\" ],\n\t\"content_scripts\": [{\n    \"matches\": [ \"http://*/*\", \"https://*/*\" ],\n    \"run_at\": \"document_start\",\n    \"js\": [\n      \"lib/jquery-ui-1.8.6/js/jquery-1.4.2.js\", \n      \"lib/jquery-ui-1.8.6/js/jquery-ui-1.8.6.highlight.js\", \n      \"js/shared.js\",\n      \"js/bit155/attr.js\",\n      \"js/bit155/scraper.js\",\n      \"js/contentscript.js\"\n    ]\n  }]\n}"
  },
  {
    "path": "src/popup.html",
    "content": "<!DOCTYPE html>\n<!-- Copyright (c) 2010, David Heaton\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n \n     * Neither the name of bit155 nor the names of its contributors\n       may be used to endorse or promote products derived from this software\n       without specific prior written permission.\n \nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -->\n<html>\n<head>\n  <title>Scraper</title>\n\n  <link rel=\"stylesheet\" href=\"lib/jquery-ui-1.8.6/css/custom-theme/jquery-ui-1.8.6.custom.css\" type=\"text/css\">\n  <link rel=\"stylesheet\" href=\"css/popup.css\" type=\"text/css\">\n\n  <script type=\"text/javascript\" src=\"lib/jquery-ui-1.8.6/js/jquery-1.4.2.js\"></script>\n  <script type=\"text/javascript\" src=\"lib/jquery-ui-1.8.6/js/jquery-ui-1.8.6.js\"></script>\n  <script type=\"text/javascript\" src=\"js/shared.js\"></script>\n  <script type=\"text/javascript\" src=\"js/bit155/attr.js\"></script>\n  <script type=\"text/javascript\" src=\"js/bit155/scraper.js\"></script>\n  <script type=\"text/javascript\" src=\"js/popup.js\"></script>\n</head>\n<body>\n  <ul id=\"presets\">\n  </ul>\n  <div id=\"footer\">\n    <a id=\"scraper\" class=\"viewer\" href=\"javascript:;\">Scraper</a>\n    <a class=\"viewer\" href=\"javascript:;\">Open...</a>\n  </div>\n</body>\n</html>"
  },
  {
    "path": "src/test/SpecRunner.html",
    "content": "<!DOCTYPE html>\n<!-- Copyright (c) 2010, David Heaton\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n \n     * Neither the name of bit155 nor the names of its contributors\n       may be used to endorse or promote products derived from this software\n       without specific prior written permission.\n \nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -->\n<html>\n<head>\n  <title>Scraper Tests</title>\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"lib/jasmine-1.0.1/jasmine.css\">\n  <script type=\"text/javascript\" src=\"lib/jasmine-1.0.1/jasmine.js\"></script>\n  <script type=\"text/javascript\" src=\"lib/jasmine-1.0.1/jasmine-html.js\"></script>\n\n  <!-- include source files here... -->\n  <script type=\"text/javascript\" src=\"../lib/jquery-ui-1.8.6/js/jquery-1.4.2.js\"></script>\n  <script type=\"text/javascript\" src=\"../lib/jquery-ui-1.8.6/js/jquery-ui-1.8.6.js\"></script>\n  <script type=\"text/javascript\" src=\"../js/shared.js\"></script>\n  <script type=\"text/javascript\" src=\"../js/bit155/csv.js\"></script>\n  <script type=\"text/javascript\" src=\"../js/bit155/attr.js\"></script>\n  <script type=\"text/javascript\" src=\"../js/bit155/scraper.js\"></script>\n\n  <!-- include spec files here... -->\n  <script type=\"text/javascript\" src=\"spec/bit155/attr.spec.js\"></script>\n  <script type=\"text/javascript\" src=\"spec/bit155/csv.spec.js\"></script>\n  <script type=\"text/javascript\" src=\"spec/bit155/scraper.spec.js\"></script>\n  <script type=\"text/javascript\" src=\"spec/jquery-serializeParams.spec.js\"></script>\n  <script type=\"text/javascript\" src=\"spec/jquery-commonAncestor.spec.js\"></script>\n  <script type=\"text/javascript\" src=\"spec/jquery-xpath.spec.js\"></script>\n</head>\n<body>\n\n<script type=\"text/javascript\">\n  jasmine.getEnv().addReporter(new jasmine.TrivialReporter());\n  jasmine.getEnv().execute();\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "src/test/lib/jasmine-1.0.1/MIT.LICENSE",
    "content": "Copyright (c) 2008-2010 Pivotal Labs\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "src/test/lib/jasmine-1.0.1/jasmine-html.js",
    "content": "jasmine.TrivialReporter = function(doc) {\n  this.document = doc || document;\n  this.suiteDivs = {};\n  this.logRunningSpecs = false;\n};\n\njasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {\n  var el = document.createElement(type);\n\n  for (var i = 2; i < arguments.length; i++) {\n    var child = arguments[i];\n\n    if (typeof child === 'string') {\n      el.appendChild(document.createTextNode(child));\n    } else {\n      if (child) { el.appendChild(child); }\n    }\n  }\n\n  for (var attr in attrs) {\n    if (attr == \"className\") {\n      el[attr] = attrs[attr];\n    } else {\n      el.setAttribute(attr, attrs[attr]);\n    }\n  }\n\n  return el;\n};\n\njasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {\n  var showPassed, showSkipped;\n\n  this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },\n      this.createDom('div', { className: 'banner' },\n        this.createDom('div', { className: 'logo' },\n            this.createDom('a', { href: 'http://pivotal.github.com/jasmine/', target: \"_blank\" }, \"Jasmine\"),\n            this.createDom('span', { className: 'version' }, runner.env.versionString())),\n        this.createDom('div', { className: 'options' },\n            \"Show \",\n            showPassed = this.createDom('input', { id: \"__jasmine_TrivialReporter_showPassed__\", type: 'checkbox' }),\n            this.createDom('label', { \"for\": \"__jasmine_TrivialReporter_showPassed__\" }, \" passed \"),\n            showSkipped = this.createDom('input', { id: \"__jasmine_TrivialReporter_showSkipped__\", type: 'checkbox' }),\n            this.createDom('label', { \"for\": \"__jasmine_TrivialReporter_showSkipped__\" }, \" skipped\")\n            )\n          ),\n\n      this.runnerDiv = this.createDom('div', { className: 'runner running' },\n          this.createDom('a', { className: 'run_spec', href: '?' }, \"run all\"),\n          this.runnerMessageSpan = this.createDom('span', {}, \"Running...\"),\n          this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, \"\"))\n      );\n\n  this.document.body.appendChild(this.outerDiv);\n\n  var suites = runner.suites();\n  for (var i = 0; i < suites.length; i++) {\n    var suite = suites[i];\n    var suiteDiv = this.createDom('div', { className: 'suite' },\n        this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, \"run\"),\n        this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));\n    this.suiteDivs[suite.id] = suiteDiv;\n    var parentDiv = this.outerDiv;\n    if (suite.parentSuite) {\n      parentDiv = this.suiteDivs[suite.parentSuite.id];\n    }\n    parentDiv.appendChild(suiteDiv);\n  }\n\n  this.startedAt = new Date();\n\n  var self = this;\n  showPassed.onclick = function(evt) {\n    if (showPassed.checked) {\n      self.outerDiv.className += ' show-passed';\n    } else {\n      self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');\n    }\n  };\n\n  showSkipped.onclick = function(evt) {\n    if (showSkipped.checked) {\n      self.outerDiv.className += ' show-skipped';\n    } else {\n      self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');\n    }\n  };\n};\n\njasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {\n  var results = runner.results();\n  var className = (results.failedCount > 0) ? \"runner failed\" : \"runner passed\";\n  this.runnerDiv.setAttribute(\"class\", className);\n  //do it twice for IE\n  this.runnerDiv.setAttribute(\"className\", className);\n  var specs = runner.specs();\n  var specCount = 0;\n  for (var i = 0; i < specs.length; i++) {\n    if (this.specFilter(specs[i])) {\n      specCount++;\n    }\n  }\n  var message = \"\" + specCount + \" spec\" + (specCount == 1 ? \"\" : \"s\" ) + \", \" + results.failedCount + \" failure\" + ((results.failedCount == 1) ? \"\" : \"s\");\n  message += \" in \" + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + \"s\";\n  this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);\n\n  this.finishedAtSpan.appendChild(document.createTextNode(\"Finished at \" + new Date().toString()));\n};\n\njasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {\n  var results = suite.results();\n  var status = results.passed() ? 'passed' : 'failed';\n  if (results.totalCount == 0) { // todo: change this to check results.skipped\n    status = 'skipped';\n  }\n  this.suiteDivs[suite.id].className += \" \" + status;\n};\n\njasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {\n  if (this.logRunningSpecs) {\n    this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');\n  }\n};\n\njasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {\n  var results = spec.results();\n  var status = results.passed() ? 'passed' : 'failed';\n  if (results.skipped) {\n    status = 'skipped';\n  }\n  var specDiv = this.createDom('div', { className: 'spec '  + status },\n      this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, \"run\"),\n      this.createDom('a', {\n        className: 'description',\n        href: '?spec=' + encodeURIComponent(spec.getFullName()),\n        title: spec.getFullName()\n      }, spec.description));\n\n\n  var resultItems = results.getItems();\n  var messagesDiv = this.createDom('div', { className: 'messages' });\n  for (var i = 0; i < resultItems.length; i++) {\n    var result = resultItems[i];\n\n    if (result.type == 'log') {\n      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));\n    } else if (result.type == 'expect' && result.passed && !result.passed()) {\n      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));\n\n      if (result.trace.stack) {\n        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));\n      }\n    }\n  }\n\n  if (messagesDiv.childNodes.length > 0) {\n    specDiv.appendChild(messagesDiv);\n  }\n\n  this.suiteDivs[spec.suite.id].appendChild(specDiv);\n};\n\njasmine.TrivialReporter.prototype.log = function() {\n  var console = jasmine.getGlobal().console;\n  if (console && console.log) {\n    if (console.log.apply) {\n      console.log.apply(console, arguments);\n    } else {\n      console.log(arguments); // ie fix: console.log.apply doesn't exist on ie\n    }\n  }\n};\n\njasmine.TrivialReporter.prototype.getLocation = function() {\n  return this.document.location;\n};\n\njasmine.TrivialReporter.prototype.specFilter = function(spec) {\n  var paramMap = {};\n  var params = this.getLocation().search.substring(1).split('&');\n  for (var i = 0; i < params.length; i++) {\n    var p = params[i].split('=');\n    paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);\n  }\n\n  if (!paramMap[\"spec\"]) return true;\n  return spec.getFullName().indexOf(paramMap[\"spec\"]) == 0;\n};\n"
  },
  {
    "path": "src/test/lib/jasmine-1.0.1/jasmine.css",
    "content": "body {\n  font-family: \"Helvetica Neue Light\", \"Lucida Grande\", \"Calibri\", \"Arial\", sans-serif;\n}\n\n\n.jasmine_reporter a:visited, .jasmine_reporter a {\n  color: #303; \n}\n\n.jasmine_reporter a:hover, .jasmine_reporter a:active {\n  color: blue; \n}\n\n.run_spec {\n  float:right;\n  padding-right: 5px;\n  font-size: .8em;\n  text-decoration: none;\n}\n\n.jasmine_reporter {\n  margin: 0 5px;\n}\n\n.banner {\n  color: #303;\n  background-color: #fef;\n  padding: 5px;\n}\n\n.logo {\n  float: left;\n  font-size: 1.1em;\n  padding-left: 5px;\n}\n\n.logo .version {\n  font-size: .6em;\n  padding-left: 1em;\n}\n\n.runner.running {\n  background-color: yellow;\n}\n\n\n.options {\n  text-align: right;\n  font-size: .8em;\n}\n\n\n\n\n.suite {\n  border: 1px outset gray;\n  margin: 5px 0;\n  padding-left: 1em;\n}\n\n.suite .suite {\n  margin: 5px; \n}\n\n.suite.passed {\n  background-color: #dfd;\n}\n\n.suite.failed {\n  background-color: #fdd;\n}\n\n.spec {\n  margin: 5px;\n  padding-left: 1em;\n  clear: both;\n}\n\n.spec.failed, .spec.passed, .spec.skipped {\n  padding-bottom: 5px;\n  border: 1px solid gray;\n}\n\n.spec.failed {\n  background-color: #fbb;\n  border-color: red;\n}\n\n.spec.passed {\n  background-color: #bfb;\n  border-color: green;\n}\n\n.spec.skipped {\n  background-color: #bbb;\n}\n\n.messages {\n  border-left: 1px dashed gray;\n  padding-left: 1em;\n  padding-right: 1em;\n}\n\n.passed {\n  background-color: #cfc;\n  display: none;\n}\n\n.failed {\n  background-color: #fbb;\n}\n\n.skipped {\n  color: #777;\n  background-color: #eee;\n  display: none;\n}\n\n\n/*.resultMessage {*/\n  /*white-space: pre;*/\n/*}*/\n\n.resultMessage span.result {\n  display: block;\n  line-height: 2em;\n  color: black;\n}\n\n.resultMessage .mismatch {\n  color: black;\n}\n\n.stackTrace {\n  white-space: pre;\n  font-size: .8em;\n  margin-left: 10px;\n  max-height: 5em;\n  overflow: auto;\n  border: 1px inset red;\n  padding: 1em;\n  background: #eef;\n}\n\n.finished-at {\n  padding-left: 1em;\n  font-size: .6em;\n}\n\n.show-passed .passed,\n.show-skipped .skipped {\n  display: block;\n}\n\n\n#jasmine_content {\n  position:fixed;\n  right: 100%;\n}\n\n.runner {\n  border: 1px solid gray;\n  display: block;\n  margin: 5px 0;\n  padding: 2px 0 2px 10px;\n}\n"
  },
  {
    "path": "src/test/lib/jasmine-1.0.1/jasmine.js",
    "content": "/**\n * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.\n *\n * @namespace\n */\nvar jasmine = {};\n\n/**\n * @private\n */\njasmine.unimplementedMethod_ = function() {\n  throw new Error(\"unimplemented method\");\n};\n\n/**\n * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just\n * a plain old variable and may be redefined by somebody else.\n *\n * @private\n */\njasmine.undefined = jasmine.___undefined___;\n\n/**\n * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.\n *\n */\njasmine.DEFAULT_UPDATE_INTERVAL = 250;\n\n/**\n * Default timeout interval in milliseconds for waitsFor() blocks.\n */\njasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;\n\njasmine.getGlobal = function() {\n  function getGlobal() {\n    return this;\n  }\n\n  return getGlobal();\n};\n\n/**\n * Allows for bound functions to be compared.  Internal use only.\n *\n * @ignore\n * @private\n * @param base {Object} bound 'this' for the function\n * @param name {Function} function to find\n */\njasmine.bindOriginal_ = function(base, name) {\n  var original = base[name];\n  if (original.apply) {\n    return function() {\n      return original.apply(base, arguments);\n    };\n  } else {\n    // IE support\n    return jasmine.getGlobal()[name];\n  }\n};\n\njasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');\njasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');\njasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');\njasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');\n\njasmine.MessageResult = function(values) {\n  this.type = 'log';\n  this.values = values;\n  this.trace = new Error(); // todo: test better\n};\n\njasmine.MessageResult.prototype.toString = function() {\n  var text = \"\";\n  for(var i = 0; i < this.values.length; i++) {\n    if (i > 0) text += \" \";\n    if (jasmine.isString_(this.values[i])) {\n      text += this.values[i];\n    } else {\n      text += jasmine.pp(this.values[i]);\n    }\n  }\n  return text;\n};\n\njasmine.ExpectationResult = function(params) {\n  this.type = 'expect';\n  this.matcherName = params.matcherName;\n  this.passed_ = params.passed;\n  this.expected = params.expected;\n  this.actual = params.actual;\n\n  this.message = this.passed_ ? 'Passed.' : params.message;\n  this.trace = this.passed_ ? '' : new Error(this.message);\n};\n\njasmine.ExpectationResult.prototype.toString = function () {\n  return this.message;\n};\n\njasmine.ExpectationResult.prototype.passed = function () {\n  return this.passed_;\n};\n\n/**\n * Getter for the Jasmine environment. Ensures one gets created\n */\njasmine.getEnv = function() {\n  return jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();\n};\n\n/**\n * @ignore\n * @private\n * @param value\n * @returns {Boolean}\n */\njasmine.isArray_ = function(value) {\n  return jasmine.isA_(\"Array\", value);  \n};\n\n/**\n * @ignore\n * @private\n * @param value\n * @returns {Boolean}\n */\njasmine.isString_ = function(value) {\n  return jasmine.isA_(\"String\", value);\n};\n\n/**\n * @ignore\n * @private\n * @param value\n * @returns {Boolean}\n */\njasmine.isNumber_ = function(value) {\n  return jasmine.isA_(\"Number\", value);\n};\n\n/**\n * @ignore\n * @private\n * @param {String} typeName\n * @param value\n * @returns {Boolean}\n */\njasmine.isA_ = function(typeName, value) {\n  return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';\n};\n\n/**\n * Pretty printer for expecations.  Takes any object and turns it into a human-readable string.\n *\n * @param value {Object} an object to be outputted\n * @returns {String}\n */\njasmine.pp = function(value) {\n  var stringPrettyPrinter = new jasmine.StringPrettyPrinter();\n  stringPrettyPrinter.format(value);\n  return stringPrettyPrinter.string;\n};\n\n/**\n * Returns true if the object is a DOM Node.\n *\n * @param {Object} obj object to check\n * @returns {Boolean}\n */\njasmine.isDomNode = function(obj) {\n  return obj['nodeType'] > 0;\n};\n\n/**\n * Returns a matchable 'generic' object of the class type.  For use in expecations of type when values don't matter.\n *\n * @example\n * // don't care about which function is passed in, as long as it's a function\n * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));\n *\n * @param {Class} clazz\n * @returns matchable object of the type clazz\n */\njasmine.any = function(clazz) {\n  return new jasmine.Matchers.Any(clazz);\n};\n\n/**\n * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.\n *\n * Spies should be created in test setup, before expectations.  They can then be checked, using the standard Jasmine\n * expectation syntax. Spies can be checked if they were called or not and what the calling params were.\n *\n * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).\n *\n * Spies are torn down at the end of every spec.\n *\n * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.\n *\n * @example\n * // a stub\n * var myStub = jasmine.createSpy('myStub');  // can be used anywhere\n *\n * // spy example\n * var foo = {\n *   not: function(bool) { return !bool; }\n * }\n *\n * // actual foo.not will not be called, execution stops\n * spyOn(foo, 'not');\n\n // foo.not spied upon, execution will continue to implementation\n * spyOn(foo, 'not').andCallThrough();\n *\n * // fake example\n * var foo = {\n *   not: function(bool) { return !bool; }\n * }\n *\n * // foo.not(val) will return val\n * spyOn(foo, 'not').andCallFake(function(value) {return value;});\n *\n * // mock example\n * foo.not(7 == 7);\n * expect(foo.not).toHaveBeenCalled();\n * expect(foo.not).toHaveBeenCalledWith(true);\n *\n * @constructor\n * @see spyOn, jasmine.createSpy, jasmine.createSpyObj\n * @param {String} name\n */\njasmine.Spy = function(name) {\n  /**\n   * The name of the spy, if provided.\n   */\n  this.identity = name || 'unknown';\n  /**\n   *  Is this Object a spy?\n   */\n  this.isSpy = true;\n  /**\n   * The actual function this spy stubs.\n   */\n  this.plan = function() {\n  };\n  /**\n   * Tracking of the most recent call to the spy.\n   * @example\n   * var mySpy = jasmine.createSpy('foo');\n   * mySpy(1, 2);\n   * mySpy.mostRecentCall.args = [1, 2];\n   */\n  this.mostRecentCall = {};\n\n  /**\n   * Holds arguments for each call to the spy, indexed by call count\n   * @example\n   * var mySpy = jasmine.createSpy('foo');\n   * mySpy(1, 2);\n   * mySpy(7, 8);\n   * mySpy.mostRecentCall.args = [7, 8];\n   * mySpy.argsForCall[0] = [1, 2];\n   * mySpy.argsForCall[1] = [7, 8];\n   */\n  this.argsForCall = [];\n  this.calls = [];\n};\n\n/**\n * Tells a spy to call through to the actual implemenatation.\n *\n * @example\n * var foo = {\n *   bar: function() { // do some stuff }\n * }\n *\n * // defining a spy on an existing property: foo.bar\n * spyOn(foo, 'bar').andCallThrough();\n */\njasmine.Spy.prototype.andCallThrough = function() {\n  this.plan = this.originalValue;\n  return this;\n};\n\n/**\n * For setting the return value of a spy.\n *\n * @example\n * // defining a spy from scratch: foo() returns 'baz'\n * var foo = jasmine.createSpy('spy on foo').andReturn('baz');\n *\n * // defining a spy on an existing property: foo.bar() returns 'baz'\n * spyOn(foo, 'bar').andReturn('baz');\n *\n * @param {Object} value\n */\njasmine.Spy.prototype.andReturn = function(value) {\n  this.plan = function() {\n    return value;\n  };\n  return this;\n};\n\n/**\n * For throwing an exception when a spy is called.\n *\n * @example\n * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'\n * var foo = jasmine.createSpy('spy on foo').andThrow('baz');\n *\n * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'\n * spyOn(foo, 'bar').andThrow('baz');\n *\n * @param {String} exceptionMsg\n */\njasmine.Spy.prototype.andThrow = function(exceptionMsg) {\n  this.plan = function() {\n    throw exceptionMsg;\n  };\n  return this;\n};\n\n/**\n * Calls an alternate implementation when a spy is called.\n *\n * @example\n * var baz = function() {\n *   // do some stuff, return something\n * }\n * // defining a spy from scratch: foo() calls the function baz\n * var foo = jasmine.createSpy('spy on foo').andCall(baz);\n *\n * // defining a spy on an existing property: foo.bar() calls an anonymnous function\n * spyOn(foo, 'bar').andCall(function() { return 'baz';} );\n *\n * @param {Function} fakeFunc\n */\njasmine.Spy.prototype.andCallFake = function(fakeFunc) {\n  this.plan = fakeFunc;\n  return this;\n};\n\n/**\n * Resets all of a spy's the tracking variables so that it can be used again.\n *\n * @example\n * spyOn(foo, 'bar');\n *\n * foo.bar();\n *\n * expect(foo.bar.callCount).toEqual(1);\n *\n * foo.bar.reset();\n *\n * expect(foo.bar.callCount).toEqual(0);\n */\njasmine.Spy.prototype.reset = function() {\n  this.wasCalled = false;\n  this.callCount = 0;\n  this.argsForCall = [];\n  this.calls = [];\n  this.mostRecentCall = {};\n};\n\njasmine.createSpy = function(name) {\n\n  var spyObj = function() {\n    spyObj.wasCalled = true;\n    spyObj.callCount++;\n    var args = jasmine.util.argsToArray(arguments);\n    spyObj.mostRecentCall.object = this;\n    spyObj.mostRecentCall.args = args;\n    spyObj.argsForCall.push(args);\n    spyObj.calls.push({object: this, args: args});\n    return spyObj.plan.apply(this, arguments);\n  };\n\n  var spy = new jasmine.Spy(name);\n\n  for (var prop in spy) {\n    spyObj[prop] = spy[prop];\n  }\n\n  spyObj.reset();\n\n  return spyObj;\n};\n\n/**\n * Determines whether an object is a spy.\n *\n * @param {jasmine.Spy|Object} putativeSpy\n * @returns {Boolean}\n */\njasmine.isSpy = function(putativeSpy) {\n  return putativeSpy && putativeSpy.isSpy;\n};\n\n/**\n * Creates a more complicated spy: an Object that has every property a function that is a spy.  Used for stubbing something\n * large in one call.\n *\n * @param {String} baseName name of spy class\n * @param {Array} methodNames array of names of methods to make spies\n */\njasmine.createSpyObj = function(baseName, methodNames) {\n  if (!jasmine.isArray_(methodNames) || methodNames.length == 0) {\n    throw new Error('createSpyObj requires a non-empty array of method names to create spies for');\n  }\n  var obj = {};\n  for (var i = 0; i < methodNames.length; i++) {\n    obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);\n  }\n  return obj;\n};\n\n/**\n * All parameters are pretty-printed and concatenated together, then written to the current spec's output.\n *\n * Be careful not to leave calls to <code>jasmine.log</code> in production code.\n */\njasmine.log = function() {\n  var spec = jasmine.getEnv().currentSpec;\n  spec.log.apply(spec, arguments);\n};\n\n/**\n * Function that installs a spy on an existing object's method name.  Used within a Spec to create a spy.\n *\n * @example\n * // spy example\n * var foo = {\n *   not: function(bool) { return !bool; }\n * }\n * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops\n *\n * @see jasmine.createSpy\n * @param obj\n * @param methodName\n * @returns a Jasmine spy that can be chained with all spy methods\n */\nvar spyOn = function(obj, methodName) {\n  return jasmine.getEnv().currentSpec.spyOn(obj, methodName);\n};\n\n/**\n * Creates a Jasmine spec that will be added to the current suite.\n *\n * // TODO: pending tests\n *\n * @example\n * it('should be true', function() {\n *   expect(true).toEqual(true);\n * });\n *\n * @param {String} desc description of this specification\n * @param {Function} func defines the preconditions and expectations of the spec\n */\nvar it = function(desc, func) {\n  return jasmine.getEnv().it(desc, func);\n};\n\n/**\n * Creates a <em>disabled</em> Jasmine spec.\n *\n * A convenience method that allows existing specs to be disabled temporarily during development.\n *\n * @param {String} desc description of this specification\n * @param {Function} func defines the preconditions and expectations of the spec\n */\nvar xit = function(desc, func) {\n  return jasmine.getEnv().xit(desc, func);\n};\n\n/**\n * Starts a chain for a Jasmine expectation.\n *\n * It is passed an Object that is the actual value and should chain to one of the many\n * jasmine.Matchers functions.\n *\n * @param {Object} actual Actual value to test against and expected value\n */\nvar expect = function(actual) {\n  return jasmine.getEnv().currentSpec.expect(actual);\n};\n\n/**\n * Defines part of a jasmine spec.  Used in cominbination with waits or waitsFor in asynchrnous specs.\n *\n * @param {Function} func Function that defines part of a jasmine spec.\n */\nvar runs = function(func) {\n  jasmine.getEnv().currentSpec.runs(func);\n};\n\n/**\n * Waits a fixed time period before moving to the next block.\n *\n * @deprecated Use waitsFor() instead\n * @param {Number} timeout milliseconds to wait\n */\nvar waits = function(timeout) {\n  jasmine.getEnv().currentSpec.waits(timeout);\n};\n\n/**\n * Waits for the latchFunction to return true before proceeding to the next block.\n *\n * @param {Function} latchFunction\n * @param {String} optional_timeoutMessage\n * @param {Number} optional_timeout\n */\nvar waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {\n  jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);\n};\n\n/**\n * A function that is called before each spec in a suite.\n *\n * Used for spec setup, including validating assumptions.\n *\n * @param {Function} beforeEachFunction\n */\nvar beforeEach = function(beforeEachFunction) {\n  jasmine.getEnv().beforeEach(beforeEachFunction);\n};\n\n/**\n * A function that is called after each spec in a suite.\n *\n * Used for restoring any state that is hijacked during spec execution.\n *\n * @param {Function} afterEachFunction\n */\nvar afterEach = function(afterEachFunction) {\n  jasmine.getEnv().afterEach(afterEachFunction);\n};\n\n/**\n * Defines a suite of specifications.\n *\n * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared\n * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization\n * of setup in some tests.\n *\n * @example\n * // TODO: a simple suite\n *\n * // TODO: a simple suite with a nested describe block\n *\n * @param {String} description A string, usually the class under test.\n * @param {Function} specDefinitions function that defines several specs.\n */\nvar describe = function(description, specDefinitions) {\n  return jasmine.getEnv().describe(description, specDefinitions);\n};\n\n/**\n * Disables a suite of specifications.  Used to disable some suites in a file, or files, temporarily during development.\n *\n * @param {String} description A string, usually the class under test.\n * @param {Function} specDefinitions function that defines several specs.\n */\nvar xdescribe = function(description, specDefinitions) {\n  return jasmine.getEnv().xdescribe(description, specDefinitions);\n};\n\n\n// Provide the XMLHttpRequest class for IE 5.x-6.x:\njasmine.XmlHttpRequest = (typeof XMLHttpRequest == \"undefined\") ? function() {\n  try {\n    return new ActiveXObject(\"Msxml2.XMLHTTP.6.0\");\n  } catch(e) {\n  }\n  try {\n    return new ActiveXObject(\"Msxml2.XMLHTTP.3.0\");\n  } catch(e) {\n  }\n  try {\n    return new ActiveXObject(\"Msxml2.XMLHTTP\");\n  } catch(e) {\n  }\n  try {\n    return new ActiveXObject(\"Microsoft.XMLHTTP\");\n  } catch(e) {\n  }\n  throw new Error(\"This browser does not support XMLHttpRequest.\");\n} : XMLHttpRequest;\n/**\n * @namespace\n */\njasmine.util = {};\n\n/**\n * Declare that a child class inherit it's prototype from the parent class.\n *\n * @private\n * @param {Function} childClass\n * @param {Function} parentClass\n */\njasmine.util.inherit = function(childClass, parentClass) {\n  /**\n   * @private\n   */\n  var subclass = function() {\n  };\n  subclass.prototype = parentClass.prototype;\n  childClass.prototype = new subclass;\n};\n\njasmine.util.formatException = function(e) {\n  var lineNumber;\n  if (e.line) {\n    lineNumber = e.line;\n  }\n  else if (e.lineNumber) {\n    lineNumber = e.lineNumber;\n  }\n\n  var file;\n\n  if (e.sourceURL) {\n    file = e.sourceURL;\n  }\n  else if (e.fileName) {\n    file = e.fileName;\n  }\n\n  var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();\n\n  if (file && lineNumber) {\n    message += ' in ' + file + ' (line ' + lineNumber + ')';\n  }\n\n  return message;\n};\n\njasmine.util.htmlEscape = function(str) {\n  if (!str) return str;\n  return str.replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;');\n};\n\njasmine.util.argsToArray = function(args) {\n  var arrayOfArgs = [];\n  for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);\n  return arrayOfArgs;\n};\n\njasmine.util.extend = function(destination, source) {\n  for (var property in source) destination[property] = source[property];\n  return destination;\n};\n\n/**\n * Environment for Jasmine\n *\n * @constructor\n */\njasmine.Env = function() {\n  this.currentSpec = null;\n  this.currentSuite = null;\n  this.currentRunner_ = new jasmine.Runner(this);\n\n  this.reporter = new jasmine.MultiReporter();\n\n  this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;\n  this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;\n  this.lastUpdate = 0;\n  this.specFilter = function() {\n    return true;\n  };\n\n  this.nextSpecId_ = 0;\n  this.nextSuiteId_ = 0;\n  this.equalityTesters_ = [];\n\n  // wrap matchers\n  this.matchersClass = function() {\n    jasmine.Matchers.apply(this, arguments);\n  };\n  jasmine.util.inherit(this.matchersClass, jasmine.Matchers);\n\n  jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);\n};\n\n\njasmine.Env.prototype.setTimeout = jasmine.setTimeout;\njasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;\njasmine.Env.prototype.setInterval = jasmine.setInterval;\njasmine.Env.prototype.clearInterval = jasmine.clearInterval;\n\n/**\n * @returns an object containing jasmine version build info, if set.\n */\njasmine.Env.prototype.version = function () {\n  if (jasmine.version_) {\n    return jasmine.version_;\n  } else {\n    throw new Error('Version not set');\n  }\n};\n\n/**\n * @returns string containing jasmine version build info, if set.\n */\njasmine.Env.prototype.versionString = function() {\n  if (jasmine.version_) {\n    var version = this.version();\n    return version.major + \".\" + version.minor + \".\" + version.build + \" revision \" + version.revision;\n  } else {\n    return \"version unknown\";\n  }\n};\n\n/**\n * @returns a sequential integer starting at 0\n */\njasmine.Env.prototype.nextSpecId = function () {\n  return this.nextSpecId_++;\n};\n\n/**\n * @returns a sequential integer starting at 0\n */\njasmine.Env.prototype.nextSuiteId = function () {\n  return this.nextSuiteId_++;\n};\n\n/**\n * Register a reporter to receive status updates from Jasmine.\n * @param {jasmine.Reporter} reporter An object which will receive status updates.\n */\njasmine.Env.prototype.addReporter = function(reporter) {\n  this.reporter.addReporter(reporter);\n};\n\njasmine.Env.prototype.execute = function() {\n  this.currentRunner_.execute();\n};\n\njasmine.Env.prototype.describe = function(description, specDefinitions) {\n  var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);\n\n  var parentSuite = this.currentSuite;\n  if (parentSuite) {\n    parentSuite.add(suite);\n  } else {\n    this.currentRunner_.add(suite);\n  }\n\n  this.currentSuite = suite;\n\n  var declarationError = null;\n  try {\n    specDefinitions.call(suite);\n  } catch(e) {\n    declarationError = e;\n  }\n\n  this.currentSuite = parentSuite;\n\n  if (declarationError) {\n    this.it(\"encountered a declaration exception\", function() {\n      throw declarationError;\n    });\n  }\n\n  return suite;\n};\n\njasmine.Env.prototype.beforeEach = function(beforeEachFunction) {\n  if (this.currentSuite) {\n    this.currentSuite.beforeEach(beforeEachFunction);\n  } else {\n    this.currentRunner_.beforeEach(beforeEachFunction);\n  }\n};\n\njasmine.Env.prototype.currentRunner = function () {\n  return this.currentRunner_;\n};\n\njasmine.Env.prototype.afterEach = function(afterEachFunction) {\n  if (this.currentSuite) {\n    this.currentSuite.afterEach(afterEachFunction);\n  } else {\n    this.currentRunner_.afterEach(afterEachFunction);\n  }\n\n};\n\njasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {\n  return {\n    execute: function() {\n    }\n  };\n};\n\njasmine.Env.prototype.it = function(description, func) {\n  var spec = new jasmine.Spec(this, this.currentSuite, description);\n  this.currentSuite.add(spec);\n  this.currentSpec = spec;\n\n  if (func) {\n    spec.runs(func);\n  }\n\n  return spec;\n};\n\njasmine.Env.prototype.xit = function(desc, func) {\n  return {\n    id: this.nextSpecId(),\n    runs: function() {\n    }\n  };\n};\n\njasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {\n  if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {\n    return true;\n  }\n\n  a.__Jasmine_been_here_before__ = b;\n  b.__Jasmine_been_here_before__ = a;\n\n  var hasKey = function(obj, keyName) {\n    return obj != null && obj[keyName] !== jasmine.undefined;\n  };\n\n  for (var property in b) {\n    if (!hasKey(a, property) && hasKey(b, property)) {\n      mismatchKeys.push(\"expected has key '\" + property + \"', but missing from actual.\");\n    }\n  }\n  for (property in a) {\n    if (!hasKey(b, property) && hasKey(a, property)) {\n      mismatchKeys.push(\"expected missing key '\" + property + \"', but present in actual.\");\n    }\n  }\n  for (property in b) {\n    if (property == '__Jasmine_been_here_before__') continue;\n    if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {\n      mismatchValues.push(\"'\" + property + \"' was '\" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + \"' in expected, but was '\" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + \"' in actual.\");\n    }\n  }\n\n  if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {\n    mismatchValues.push(\"arrays were not the same length\");\n  }\n\n  delete a.__Jasmine_been_here_before__;\n  delete b.__Jasmine_been_here_before__;\n  return (mismatchKeys.length == 0 && mismatchValues.length == 0);\n};\n\njasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {\n  mismatchKeys = mismatchKeys || [];\n  mismatchValues = mismatchValues || [];\n\n  for (var i = 0; i < this.equalityTesters_.length; i++) {\n    var equalityTester = this.equalityTesters_[i];\n    var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);\n    if (result !== jasmine.undefined) return result;\n  }\n\n  if (a === b) return true;\n\n  if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {\n    return (a == jasmine.undefined && b == jasmine.undefined);\n  }\n\n  if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {\n    return a === b;\n  }\n\n  if (a instanceof Date && b instanceof Date) {\n    return a.getTime() == b.getTime();\n  }\n\n  if (a instanceof jasmine.Matchers.Any) {\n    return a.matches(b);\n  }\n\n  if (b instanceof jasmine.Matchers.Any) {\n    return b.matches(a);\n  }\n\n  if (jasmine.isString_(a) && jasmine.isString_(b)) {\n    return (a == b);\n  }\n\n  if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {\n    return (a == b);\n  }\n\n  if (typeof a === \"object\" && typeof b === \"object\") {\n    return this.compareObjects_(a, b, mismatchKeys, mismatchValues);\n  }\n\n  //Straight check\n  return (a === b);\n};\n\njasmine.Env.prototype.contains_ = function(haystack, needle) {\n  if (jasmine.isArray_(haystack)) {\n    for (var i = 0; i < haystack.length; i++) {\n      if (this.equals_(haystack[i], needle)) return true;\n    }\n    return false;\n  }\n  return haystack.indexOf(needle) >= 0;\n};\n\njasmine.Env.prototype.addEqualityTester = function(equalityTester) {\n  this.equalityTesters_.push(equalityTester);\n};\n/** No-op base class for Jasmine reporters.\n *\n * @constructor\n */\njasmine.Reporter = function() {\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.Reporter.prototype.reportRunnerStarting = function(runner) {\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.Reporter.prototype.reportRunnerResults = function(runner) {\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.Reporter.prototype.reportSuiteResults = function(suite) {\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.Reporter.prototype.reportSpecStarting = function(spec) {\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.Reporter.prototype.reportSpecResults = function(spec) {\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.Reporter.prototype.log = function(str) {\n};\n\n/**\n * Blocks are functions with executable code that make up a spec.\n *\n * @constructor\n * @param {jasmine.Env} env\n * @param {Function} func\n * @param {jasmine.Spec} spec\n */\njasmine.Block = function(env, func, spec) {\n  this.env = env;\n  this.func = func;\n  this.spec = spec;\n};\n\njasmine.Block.prototype.execute = function(onComplete) {  \n  try {\n    this.func.apply(this.spec);\n  } catch (e) {\n    this.spec.fail(e);\n  }\n  onComplete();\n};\n/** JavaScript API reporter.\n *\n * @constructor\n */\njasmine.JsApiReporter = function() {\n  this.started = false;\n  this.finished = false;\n  this.suites_ = [];\n  this.results_ = {};\n};\n\njasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {\n  this.started = true;\n  var suites = runner.topLevelSuites();\n  for (var i = 0; i < suites.length; i++) {\n    var suite = suites[i];\n    this.suites_.push(this.summarize_(suite));\n  }\n};\n\njasmine.JsApiReporter.prototype.suites = function() {\n  return this.suites_;\n};\n\njasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {\n  var isSuite = suiteOrSpec instanceof jasmine.Suite;\n  var summary = {\n    id: suiteOrSpec.id,\n    name: suiteOrSpec.description,\n    type: isSuite ? 'suite' : 'spec',\n    children: []\n  };\n  \n  if (isSuite) {\n    var children = suiteOrSpec.children();\n    for (var i = 0; i < children.length; i++) {\n      summary.children.push(this.summarize_(children[i]));\n    }\n  }\n  return summary;\n};\n\njasmine.JsApiReporter.prototype.results = function() {\n  return this.results_;\n};\n\njasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {\n  return this.results_[specId];\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {\n  this.finished = true;\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {\n  this.results_[spec.id] = {\n    messages: spec.results().getItems(),\n    result: spec.results().failedCount > 0 ? \"failed\" : \"passed\"\n  };\n};\n\n//noinspection JSUnusedLocalSymbols\njasmine.JsApiReporter.prototype.log = function(str) {\n};\n\njasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){\n  var results = {};\n  for (var i = 0; i < specIds.length; i++) {\n    var specId = specIds[i];\n    results[specId] = this.summarizeResult_(this.results_[specId]);\n  }\n  return results;\n};\n\njasmine.JsApiReporter.prototype.summarizeResult_ = function(result){\n  var summaryMessages = [];\n  var messagesLength = result.messages.length;\n  for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {\n    var resultMessage = result.messages[messageIndex];\n    summaryMessages.push({\n      text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,\n      passed: resultMessage.passed ? resultMessage.passed() : true,\n      type: resultMessage.type,\n      message: resultMessage.message,\n      trace: {\n        stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined\n      }\n    });\n  }\n\n  return {\n    result : result.result,\n    messages : summaryMessages\n  };\n};\n\n/**\n * @constructor\n * @param {jasmine.Env} env\n * @param actual\n * @param {jasmine.Spec} spec\n */\njasmine.Matchers = function(env, actual, spec, opt_isNot) {\n  this.env = env;\n  this.actual = actual;\n  this.spec = spec;\n  this.isNot = opt_isNot || false;\n  this.reportWasCalled_ = false;\n};\n\n// todo: @deprecated as of Jasmine 0.11, remove soon [xw]\njasmine.Matchers.pp = function(str) {\n  throw new Error(\"jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!\");\n};\n\n// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]\njasmine.Matchers.prototype.report = function(result, failing_message, details) {\n  throw new Error(\"As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs\");\n};\n\njasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {\n  for (var methodName in prototype) {\n    if (methodName == 'report') continue;\n    var orig = prototype[methodName];\n    matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);\n  }\n};\n\njasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {\n  return function() {\n    var matcherArgs = jasmine.util.argsToArray(arguments);\n    var result = matcherFunction.apply(this, arguments);\n\n    if (this.isNot) {\n      result = !result;\n    }\n\n    if (this.reportWasCalled_) return result;\n\n    var message;\n    if (!result) {\n      if (this.message) {\n        message = this.message.apply(this, arguments);\n        if (jasmine.isArray_(message)) {\n          message = message[this.isNot ? 1 : 0];\n        }\n      } else {\n        var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });\n        message = \"Expected \" + jasmine.pp(this.actual) + (this.isNot ? \" not \" : \" \") + englishyPredicate;\n        if (matcherArgs.length > 0) {\n          for (var i = 0; i < matcherArgs.length; i++) {\n            if (i > 0) message += \",\";\n            message += \" \" + jasmine.pp(matcherArgs[i]);\n          }\n        }\n        message += \".\";\n      }\n    }\n    var expectationResult = new jasmine.ExpectationResult({\n      matcherName: matcherName,\n      passed: result,\n      expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],\n      actual: this.actual,\n      message: message\n    });\n    this.spec.addMatcherResult(expectationResult);\n    return jasmine.undefined;\n  };\n};\n\n\n\n\n/**\n * toBe: compares the actual to the expected using ===\n * @param expected\n */\njasmine.Matchers.prototype.toBe = function(expected) {\n  return this.actual === expected;\n};\n\n/**\n * toNotBe: compares the actual to the expected using !==\n * @param expected\n * @deprecated as of 1.0. Use not.toBe() instead.\n */\njasmine.Matchers.prototype.toNotBe = function(expected) {\n  return this.actual !== expected;\n};\n\n/**\n * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.\n *\n * @param expected\n */\njasmine.Matchers.prototype.toEqual = function(expected) {\n  return this.env.equals_(this.actual, expected);\n};\n\n/**\n * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual\n * @param expected\n * @deprecated as of 1.0. Use not.toNotEqual() instead.\n */\njasmine.Matchers.prototype.toNotEqual = function(expected) {\n  return !this.env.equals_(this.actual, expected);\n};\n\n/**\n * Matcher that compares the actual to the expected using a regular expression.  Constructs a RegExp, so takes\n * a pattern or a String.\n *\n * @param expected\n */\njasmine.Matchers.prototype.toMatch = function(expected) {\n  return new RegExp(expected).test(this.actual);\n};\n\n/**\n * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch\n * @param expected\n * @deprecated as of 1.0. Use not.toMatch() instead.\n */\njasmine.Matchers.prototype.toNotMatch = function(expected) {\n  return !(new RegExp(expected).test(this.actual));\n};\n\n/**\n * Matcher that compares the actual to jasmine.undefined.\n */\njasmine.Matchers.prototype.toBeDefined = function() {\n  return (this.actual !== jasmine.undefined);\n};\n\n/**\n * Matcher that compares the actual to jasmine.undefined.\n */\njasmine.Matchers.prototype.toBeUndefined = function() {\n  return (this.actual === jasmine.undefined);\n};\n\n/**\n * Matcher that compares the actual to null.\n */\njasmine.Matchers.prototype.toBeNull = function() {\n  return (this.actual === null);\n};\n\n/**\n * Matcher that boolean not-nots the actual.\n */\njasmine.Matchers.prototype.toBeTruthy = function() {\n  return !!this.actual;\n};\n\n\n/**\n * Matcher that boolean nots the actual.\n */\njasmine.Matchers.prototype.toBeFalsy = function() {\n  return !this.actual;\n};\n\n\n/**\n * Matcher that checks to see if the actual, a Jasmine spy, was called.\n */\njasmine.Matchers.prototype.toHaveBeenCalled = function() {\n  if (arguments.length > 0) {\n    throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');\n  }\n\n  if (!jasmine.isSpy(this.actual)) {\n    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');\n  }\n\n  this.message = function() {\n    return [\n      \"Expected spy \" + this.actual.identity + \" to have been called.\",\n      \"Expected spy \" + this.actual.identity + \" not to have been called.\"\n    ];\n  };\n\n  return this.actual.wasCalled;\n};\n\n/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */\njasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;\n\n/**\n * Matcher that checks to see if the actual, a Jasmine spy, was not called.\n *\n * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead\n */\njasmine.Matchers.prototype.wasNotCalled = function() {\n  if (arguments.length > 0) {\n    throw new Error('wasNotCalled does not take arguments');\n  }\n\n  if (!jasmine.isSpy(this.actual)) {\n    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');\n  }\n\n  this.message = function() {\n    return [\n      \"Expected spy \" + this.actual.identity + \" to not have been called.\",\n      \"Expected spy \" + this.actual.identity + \" to have been called.\"\n    ];\n  };\n\n  return !this.actual.wasCalled;\n};\n\n/**\n * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.\n *\n * @example\n *\n */\njasmine.Matchers.prototype.toHaveBeenCalledWith = function() {\n  var expectedArgs = jasmine.util.argsToArray(arguments);\n  if (!jasmine.isSpy(this.actual)) {\n    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');\n  }\n  this.message = function() {\n    if (this.actual.callCount == 0) {\n      // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]\n      return [\n        \"Expected spy to have been called with \" + jasmine.pp(expectedArgs) + \" but it was never called.\",\n        \"Expected spy not to have been called with \" + jasmine.pp(expectedArgs) + \" but it was.\"\n      ];\n    } else {\n      return [\n        \"Expected spy to have been called with \" + jasmine.pp(expectedArgs) + \" but was called with \" + jasmine.pp(this.actual.argsForCall),\n        \"Expected spy not to have been called with \" + jasmine.pp(expectedArgs) + \" but was called with \" + jasmine.pp(this.actual.argsForCall)\n      ];\n    }\n  };\n\n  return this.env.contains_(this.actual.argsForCall, expectedArgs);\n};\n\n/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */\njasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;\n\n/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */\njasmine.Matchers.prototype.wasNotCalledWith = function() {\n  var expectedArgs = jasmine.util.argsToArray(arguments);\n  if (!jasmine.isSpy(this.actual)) {\n    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');\n  }\n\n  this.message = function() {\n    return [\n      \"Expected spy not to have been called with \" + jasmine.pp(expectedArgs) + \" but it was\",\n      \"Expected spy to have been called with \" + jasmine.pp(expectedArgs) + \" but it was\"\n    ]\n  };\n\n  return !this.env.contains_(this.actual.argsForCall, expectedArgs);\n};\n\n/**\n * Matcher that checks that the expected item is an element in the actual Array.\n *\n * @param {Object} expected\n */\njasmine.Matchers.prototype.toContain = function(expected) {\n  return this.env.contains_(this.actual, expected);\n};\n\n/**\n * Matcher that checks that the expected item is NOT an element in the actual Array.\n *\n * @param {Object} expected\n * @deprecated as of 1.0. Use not.toNotContain() instead.\n */\njasmine.Matchers.prototype.toNotContain = function(expected) {\n  return !this.env.contains_(this.actual, expected);\n};\n\njasmine.Matchers.prototype.toBeLessThan = function(expected) {\n  return this.actual < expected;\n};\n\njasmine.Matchers.prototype.toBeGreaterThan = function(expected) {\n  return this.actual > expected;\n};\n\n/**\n * Matcher that checks that the expected exception was thrown by the actual.\n *\n * @param {String} expected\n */\njasmine.Matchers.prototype.toThrow = function(expected) {\n  var result = false;\n  var exception;\n  if (typeof this.actual != 'function') {\n    throw new Error('Actual is not a function');\n  }\n  try {\n    this.actual();\n  } catch (e) {\n    exception = e;\n  }\n  if (exception) {\n    result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));\n  }\n\n  var not = this.isNot ? \"not \" : \"\";\n\n  this.message = function() {\n    if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {\n      return [\"Expected function \" + not + \"to throw\", expected ? expected.message || expected : \" an exception\", \", but it threw\", exception.message || exception].join(' ');\n    } else {\n      return \"Expected function to throw an exception.\";\n    }\n  };\n\n  return result;\n};\n\njasmine.Matchers.Any = function(expectedClass) {\n  this.expectedClass = expectedClass;\n};\n\njasmine.Matchers.Any.prototype.matches = function(other) {\n  if (this.expectedClass == String) {\n    return typeof other == 'string' || other instanceof String;\n  }\n\n  if (this.expectedClass == Number) {\n    return typeof other == 'number' || other instanceof Number;\n  }\n\n  if (this.expectedClass == Function) {\n    return typeof other == 'function' || other instanceof Function;\n  }\n\n  if (this.expectedClass == Object) {\n    return typeof other == 'object';\n  }\n\n  return other instanceof this.expectedClass;\n};\n\njasmine.Matchers.Any.prototype.toString = function() {\n  return '<jasmine.any(' + this.expectedClass + ')>';\n};\n\n/**\n * @constructor\n */\njasmine.MultiReporter = function() {\n  this.subReporters_ = [];\n};\njasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);\n\njasmine.MultiReporter.prototype.addReporter = function(reporter) {\n  this.subReporters_.push(reporter);\n};\n\n(function() {\n  var functionNames = [\n    \"reportRunnerStarting\",\n    \"reportRunnerResults\",\n    \"reportSuiteResults\",\n    \"reportSpecStarting\",\n    \"reportSpecResults\",\n    \"log\"\n  ];\n  for (var i = 0; i < functionNames.length; i++) {\n    var functionName = functionNames[i];\n    jasmine.MultiReporter.prototype[functionName] = (function(functionName) {\n      return function() {\n        for (var j = 0; j < this.subReporters_.length; j++) {\n          var subReporter = this.subReporters_[j];\n          if (subReporter[functionName]) {\n            subReporter[functionName].apply(subReporter, arguments);\n          }\n        }\n      };\n    })(functionName);\n  }\n})();\n/**\n * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults\n *\n * @constructor\n */\njasmine.NestedResults = function() {\n  /**\n   * The total count of results\n   */\n  this.totalCount = 0;\n  /**\n   * Number of passed results\n   */\n  this.passedCount = 0;\n  /**\n   * Number of failed results\n   */\n  this.failedCount = 0;\n  /**\n   * Was this suite/spec skipped?\n   */\n  this.skipped = false;\n  /**\n   * @ignore\n   */\n  this.items_ = [];\n};\n\n/**\n * Roll up the result counts.\n *\n * @param result\n */\njasmine.NestedResults.prototype.rollupCounts = function(result) {\n  this.totalCount += result.totalCount;\n  this.passedCount += result.passedCount;\n  this.failedCount += result.failedCount;\n};\n\n/**\n * Adds a log message.\n * @param values Array of message parts which will be concatenated later.\n */\njasmine.NestedResults.prototype.log = function(values) {\n  this.items_.push(new jasmine.MessageResult(values));\n};\n\n/**\n * Getter for the results: message & results.\n */\njasmine.NestedResults.prototype.getItems = function() {\n  return this.items_;\n};\n\n/**\n * Adds a result, tracking counts (total, passed, & failed)\n * @param {jasmine.ExpectationResult|jasmine.NestedResults} result\n */\njasmine.NestedResults.prototype.addResult = function(result) {\n  if (result.type != 'log') {\n    if (result.items_) {\n      this.rollupCounts(result);\n    } else {\n      this.totalCount++;\n      if (result.passed()) {\n        this.passedCount++;\n      } else {\n        this.failedCount++;\n      }\n    }\n  }\n  this.items_.push(result);\n};\n\n/**\n * @returns {Boolean} True if <b>everything</b> below passed\n */\njasmine.NestedResults.prototype.passed = function() {\n  return this.passedCount === this.totalCount;\n};\n/**\n * Base class for pretty printing for expectation results.\n */\njasmine.PrettyPrinter = function() {\n  this.ppNestLevel_ = 0;\n};\n\n/**\n * Formats a value in a nice, human-readable string.\n *\n * @param value\n */\njasmine.PrettyPrinter.prototype.format = function(value) {\n  if (this.ppNestLevel_ > 40) {\n    throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');\n  }\n\n  this.ppNestLevel_++;\n  try {\n    if (value === jasmine.undefined) {\n      this.emitScalar('undefined');\n    } else if (value === null) {\n      this.emitScalar('null');\n    } else if (value === jasmine.getGlobal()) {\n      this.emitScalar('<global>');\n    } else if (value instanceof jasmine.Matchers.Any) {\n      this.emitScalar(value.toString());\n    } else if (typeof value === 'string') {\n      this.emitString(value);\n    } else if (jasmine.isSpy(value)) {\n      this.emitScalar(\"spy on \" + value.identity);\n    } else if (value instanceof RegExp) {\n      this.emitScalar(value.toString());\n    } else if (typeof value === 'function') {\n      this.emitScalar('Function');\n    } else if (typeof value.nodeType === 'number') {\n      this.emitScalar('HTMLNode');\n    } else if (value instanceof Date) {\n      this.emitScalar('Date(' + value + ')');\n    } else if (value.__Jasmine_been_here_before__) {\n      this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');\n    } else if (jasmine.isArray_(value) || typeof value == 'object') {\n      value.__Jasmine_been_here_before__ = true;\n      if (jasmine.isArray_(value)) {\n        this.emitArray(value);\n      } else {\n        this.emitObject(value);\n      }\n      delete value.__Jasmine_been_here_before__;\n    } else {\n      this.emitScalar(value.toString());\n    }\n  } finally {\n    this.ppNestLevel_--;\n  }\n};\n\njasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {\n  for (var property in obj) {\n    if (property == '__Jasmine_been_here_before__') continue;\n    fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) != null) : false);\n  }\n};\n\njasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;\njasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;\njasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;\njasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;\n\njasmine.StringPrettyPrinter = function() {\n  jasmine.PrettyPrinter.call(this);\n\n  this.string = '';\n};\njasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);\n\njasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {\n  this.append(value);\n};\n\njasmine.StringPrettyPrinter.prototype.emitString = function(value) {\n  this.append(\"'\" + value + \"'\");\n};\n\njasmine.StringPrettyPrinter.prototype.emitArray = function(array) {\n  this.append('[ ');\n  for (var i = 0; i < array.length; i++) {\n    if (i > 0) {\n      this.append(', ');\n    }\n    this.format(array[i]);\n  }\n  this.append(' ]');\n};\n\njasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {\n  var self = this;\n  this.append('{ ');\n  var first = true;\n\n  this.iterateObject(obj, function(property, isGetter) {\n    if (first) {\n      first = false;\n    } else {\n      self.append(', ');\n    }\n\n    self.append(property);\n    self.append(' : ');\n    if (isGetter) {\n      self.append('<getter>');\n    } else {\n      self.format(obj[property]);\n    }\n  });\n\n  this.append(' }');\n};\n\njasmine.StringPrettyPrinter.prototype.append = function(value) {\n  this.string += value;\n};\njasmine.Queue = function(env) {\n  this.env = env;\n  this.blocks = [];\n  this.running = false;\n  this.index = 0;\n  this.offset = 0;\n  this.abort = false;\n};\n\njasmine.Queue.prototype.addBefore = function(block) {\n  this.blocks.unshift(block);\n};\n\njasmine.Queue.prototype.add = function(block) {\n  this.blocks.push(block);\n};\n\njasmine.Queue.prototype.insertNext = function(block) {\n  this.blocks.splice((this.index + this.offset + 1), 0, block);\n  this.offset++;\n};\n\njasmine.Queue.prototype.start = function(onComplete) {\n  this.running = true;\n  this.onComplete = onComplete;\n  this.next_();\n};\n\njasmine.Queue.prototype.isRunning = function() {\n  return this.running;\n};\n\njasmine.Queue.LOOP_DONT_RECURSE = true;\n\njasmine.Queue.prototype.next_ = function() {\n  var self = this;\n  var goAgain = true;\n\n  while (goAgain) {\n    goAgain = false;\n    \n    if (self.index < self.blocks.length && !this.abort) {\n      var calledSynchronously = true;\n      var completedSynchronously = false;\n\n      var onComplete = function () {\n        if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {\n          completedSynchronously = true;\n          return;\n        }\n\n        if (self.blocks[self.index].abort) {\n          self.abort = true;\n        }\n\n        self.offset = 0;\n        self.index++;\n\n        var now = new Date().getTime();\n        if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {\n          self.env.lastUpdate = now;\n          self.env.setTimeout(function() {\n            self.next_();\n          }, 0);\n        } else {\n          if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {\n            goAgain = true;\n          } else {\n            self.next_();\n          }\n        }\n      };\n      self.blocks[self.index].execute(onComplete);\n\n      calledSynchronously = false;\n      if (completedSynchronously) {\n        onComplete();\n      }\n      \n    } else {\n      self.running = false;\n      if (self.onComplete) {\n        self.onComplete();\n      }\n    }\n  }\n};\n\njasmine.Queue.prototype.results = function() {\n  var results = new jasmine.NestedResults();\n  for (var i = 0; i < this.blocks.length; i++) {\n    if (this.blocks[i].results) {\n      results.addResult(this.blocks[i].results());\n    }\n  }\n  return results;\n};\n\n\n/**\n * Runner\n *\n * @constructor\n * @param {jasmine.Env} env\n */\njasmine.Runner = function(env) {\n  var self = this;\n  self.env = env;\n  self.queue = new jasmine.Queue(env);\n  self.before_ = [];\n  self.after_ = [];\n  self.suites_ = [];\n};\n\njasmine.Runner.prototype.execute = function() {\n  var self = this;\n  if (self.env.reporter.reportRunnerStarting) {\n    self.env.reporter.reportRunnerStarting(this);\n  }\n  self.queue.start(function () {\n    self.finishCallback();\n  });\n};\n\njasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {\n  beforeEachFunction.typeName = 'beforeEach';\n  this.before_.splice(0,0,beforeEachFunction);\n};\n\njasmine.Runner.prototype.afterEach = function(afterEachFunction) {\n  afterEachFunction.typeName = 'afterEach';\n  this.after_.splice(0,0,afterEachFunction);\n};\n\n\njasmine.Runner.prototype.finishCallback = function() {\n  this.env.reporter.reportRunnerResults(this);\n};\n\njasmine.Runner.prototype.addSuite = function(suite) {\n  this.suites_.push(suite);\n};\n\njasmine.Runner.prototype.add = function(block) {\n  if (block instanceof jasmine.Suite) {\n    this.addSuite(block);\n  }\n  this.queue.add(block);\n};\n\njasmine.Runner.prototype.specs = function () {\n  var suites = this.suites();\n  var specs = [];\n  for (var i = 0; i < suites.length; i++) {\n    specs = specs.concat(suites[i].specs());\n  }\n  return specs;\n};\n\njasmine.Runner.prototype.suites = function() {\n  return this.suites_;\n};\n\njasmine.Runner.prototype.topLevelSuites = function() {\n  var topLevelSuites = [];\n  for (var i = 0; i < this.suites_.length; i++) {\n    if (!this.suites_[i].parentSuite) {\n      topLevelSuites.push(this.suites_[i]);\n    }\n  }\n  return topLevelSuites;\n};\n\njasmine.Runner.prototype.results = function() {\n  return this.queue.results();\n};\n/**\n * Internal representation of a Jasmine specification, or test.\n *\n * @constructor\n * @param {jasmine.Env} env\n * @param {jasmine.Suite} suite\n * @param {String} description\n */\njasmine.Spec = function(env, suite, description) {\n  if (!env) {\n    throw new Error('jasmine.Env() required');\n  }\n  if (!suite) {\n    throw new Error('jasmine.Suite() required');\n  }\n  var spec = this;\n  spec.id = env.nextSpecId ? env.nextSpecId() : null;\n  spec.env = env;\n  spec.suite = suite;\n  spec.description = description;\n  spec.queue = new jasmine.Queue(env);\n\n  spec.afterCallbacks = [];\n  spec.spies_ = [];\n\n  spec.results_ = new jasmine.NestedResults();\n  spec.results_.description = description;\n  spec.matchersClass = null;\n};\n\njasmine.Spec.prototype.getFullName = function() {\n  return this.suite.getFullName() + ' ' + this.description + '.';\n};\n\n\njasmine.Spec.prototype.results = function() {\n  return this.results_;\n};\n\n/**\n * All parameters are pretty-printed and concatenated together, then written to the spec's output.\n *\n * Be careful not to leave calls to <code>jasmine.log</code> in production code.\n */\njasmine.Spec.prototype.log = function() {\n  return this.results_.log(arguments);\n};\n\njasmine.Spec.prototype.runs = function (func) {\n  var block = new jasmine.Block(this.env, func, this);\n  this.addToQueue(block);\n  return this;\n};\n\njasmine.Spec.prototype.addToQueue = function (block) {\n  if (this.queue.isRunning()) {\n    this.queue.insertNext(block);\n  } else {\n    this.queue.add(block);\n  }\n};\n\n/**\n * @param {jasmine.ExpectationResult} result\n */\njasmine.Spec.prototype.addMatcherResult = function(result) {\n  this.results_.addResult(result);\n};\n\njasmine.Spec.prototype.expect = function(actual) {\n  var positive = new (this.getMatchersClass_())(this.env, actual, this);\n  positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);\n  return positive;\n};\n\n/**\n * Waits a fixed time period before moving to the next block.\n *\n * @deprecated Use waitsFor() instead\n * @param {Number} timeout milliseconds to wait\n */\njasmine.Spec.prototype.waits = function(timeout) {\n  var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);\n  this.addToQueue(waitsFunc);\n  return this;\n};\n\n/**\n * Waits for the latchFunction to return true before proceeding to the next block.\n *\n * @param {Function} latchFunction\n * @param {String} optional_timeoutMessage\n * @param {Number} optional_timeout\n */\njasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {\n  var latchFunction_ = null;\n  var optional_timeoutMessage_ = null;\n  var optional_timeout_ = null;\n\n  for (var i = 0; i < arguments.length; i++) {\n    var arg = arguments[i];\n    switch (typeof arg) {\n      case 'function':\n        latchFunction_ = arg;\n        break;\n      case 'string':\n        optional_timeoutMessage_ = arg;\n        break;\n      case 'number':\n        optional_timeout_ = arg;\n        break;\n    }\n  }\n\n  var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);\n  this.addToQueue(waitsForFunc);\n  return this;\n};\n\njasmine.Spec.prototype.fail = function (e) {\n  var expectationResult = new jasmine.ExpectationResult({\n    passed: false,\n    message: e ? jasmine.util.formatException(e) : 'Exception'\n  });\n  this.results_.addResult(expectationResult);\n};\n\njasmine.Spec.prototype.getMatchersClass_ = function() {\n  return this.matchersClass || this.env.matchersClass;\n};\n\njasmine.Spec.prototype.addMatchers = function(matchersPrototype) {\n  var parent = this.getMatchersClass_();\n  var newMatchersClass = function() {\n    parent.apply(this, arguments);\n  };\n  jasmine.util.inherit(newMatchersClass, parent);\n  jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);\n  this.matchersClass = newMatchersClass;\n};\n\njasmine.Spec.prototype.finishCallback = function() {\n  this.env.reporter.reportSpecResults(this);\n};\n\njasmine.Spec.prototype.finish = function(onComplete) {\n  this.removeAllSpies();\n  this.finishCallback();\n  if (onComplete) {\n    onComplete();\n  }\n};\n\njasmine.Spec.prototype.after = function(doAfter) {\n  if (this.queue.isRunning()) {\n    this.queue.add(new jasmine.Block(this.env, doAfter, this));\n  } else {\n    this.afterCallbacks.unshift(doAfter);\n  }\n};\n\njasmine.Spec.prototype.execute = function(onComplete) {\n  var spec = this;\n  if (!spec.env.specFilter(spec)) {\n    spec.results_.skipped = true;\n    spec.finish(onComplete);\n    return;\n  }\n\n  this.env.reporter.reportSpecStarting(this);\n\n  spec.env.currentSpec = spec;\n\n  spec.addBeforesAndAftersToQueue();\n\n  spec.queue.start(function () {\n    spec.finish(onComplete);\n  });\n};\n\njasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {\n  var runner = this.env.currentRunner();\n  var i;\n\n  for (var suite = this.suite; suite; suite = suite.parentSuite) {\n    for (i = 0; i < suite.before_.length; i++) {\n      this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));\n    }\n  }\n  for (i = 0; i < runner.before_.length; i++) {\n    this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));\n  }\n  for (i = 0; i < this.afterCallbacks.length; i++) {\n    this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));\n  }\n  for (suite = this.suite; suite; suite = suite.parentSuite) {\n    for (i = 0; i < suite.after_.length; i++) {\n      this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));\n    }\n  }\n  for (i = 0; i < runner.after_.length; i++) {\n    this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));\n  }\n};\n\njasmine.Spec.prototype.explodes = function() {\n  throw 'explodes function should not have been called';\n};\n\njasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {\n  if (obj == jasmine.undefined) {\n    throw \"spyOn could not find an object to spy upon for \" + methodName + \"()\";\n  }\n\n  if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {\n    throw methodName + '() method does not exist';\n  }\n\n  if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {\n    throw new Error(methodName + ' has already been spied upon');\n  }\n\n  var spyObj = jasmine.createSpy(methodName);\n\n  this.spies_.push(spyObj);\n  spyObj.baseObj = obj;\n  spyObj.methodName = methodName;\n  spyObj.originalValue = obj[methodName];\n\n  obj[methodName] = spyObj;\n\n  return spyObj;\n};\n\njasmine.Spec.prototype.removeAllSpies = function() {\n  for (var i = 0; i < this.spies_.length; i++) {\n    var spy = this.spies_[i];\n    spy.baseObj[spy.methodName] = spy.originalValue;\n  }\n  this.spies_ = [];\n};\n\n/**\n * Internal representation of a Jasmine suite.\n *\n * @constructor\n * @param {jasmine.Env} env\n * @param {String} description\n * @param {Function} specDefinitions\n * @param {jasmine.Suite} parentSuite\n */\njasmine.Suite = function(env, description, specDefinitions, parentSuite) {\n  var self = this;\n  self.id = env.nextSuiteId ? env.nextSuiteId() : null;\n  self.description = description;\n  self.queue = new jasmine.Queue(env);\n  self.parentSuite = parentSuite;\n  self.env = env;\n  self.before_ = [];\n  self.after_ = [];\n  self.children_ = [];\n  self.suites_ = [];\n  self.specs_ = [];\n};\n\njasmine.Suite.prototype.getFullName = function() {\n  var fullName = this.description;\n  for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {\n    fullName = parentSuite.description + ' ' + fullName;\n  }\n  return fullName;\n};\n\njasmine.Suite.prototype.finish = function(onComplete) {\n  this.env.reporter.reportSuiteResults(this);\n  this.finished = true;\n  if (typeof(onComplete) == 'function') {\n    onComplete();\n  }\n};\n\njasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {\n  beforeEachFunction.typeName = 'beforeEach';\n  this.before_.unshift(beforeEachFunction);\n};\n\njasmine.Suite.prototype.afterEach = function(afterEachFunction) {\n  afterEachFunction.typeName = 'afterEach';\n  this.after_.unshift(afterEachFunction);\n};\n\njasmine.Suite.prototype.results = function() {\n  return this.queue.results();\n};\n\njasmine.Suite.prototype.add = function(suiteOrSpec) {\n  this.children_.push(suiteOrSpec);\n  if (suiteOrSpec instanceof jasmine.Suite) {\n    this.suites_.push(suiteOrSpec);\n    this.env.currentRunner().addSuite(suiteOrSpec);\n  } else {\n    this.specs_.push(suiteOrSpec);\n  }\n  this.queue.add(suiteOrSpec);\n};\n\njasmine.Suite.prototype.specs = function() {\n  return this.specs_;\n};\n\njasmine.Suite.prototype.suites = function() {\n  return this.suites_;\n};\n\njasmine.Suite.prototype.children = function() {\n  return this.children_;\n};\n\njasmine.Suite.prototype.execute = function(onComplete) {\n  var self = this;\n  this.queue.start(function () {\n    self.finish(onComplete);\n  });\n};\njasmine.WaitsBlock = function(env, timeout, spec) {\n  this.timeout = timeout;\n  jasmine.Block.call(this, env, null, spec);\n};\n\njasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);\n\njasmine.WaitsBlock.prototype.execute = function (onComplete) {\n  this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');\n  this.env.setTimeout(function () {\n    onComplete();\n  }, this.timeout);\n};\n/**\n * A block which waits for some condition to become true, with timeout.\n *\n * @constructor\n * @extends jasmine.Block\n * @param {jasmine.Env} env The Jasmine environment.\n * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.\n * @param {Function} latchFunction A function which returns true when the desired condition has been met.\n * @param {String} message The message to display if the desired condition hasn't been met within the given time period.\n * @param {jasmine.Spec} spec The Jasmine spec.\n */\njasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {\n  this.timeout = timeout || env.defaultTimeoutInterval;\n  this.latchFunction = latchFunction;\n  this.message = message;\n  this.totalTimeSpentWaitingForLatch = 0;\n  jasmine.Block.call(this, env, null, spec);\n};\njasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);\n\njasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;\n\njasmine.WaitsForBlock.prototype.execute = function(onComplete) {\n  this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));\n  var latchFunctionResult;\n  try {\n    latchFunctionResult = this.latchFunction.apply(this.spec);\n  } catch (e) {\n    this.spec.fail(e);\n    onComplete();\n    return;\n  }\n\n  if (latchFunctionResult) {\n    onComplete();\n  } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {\n    var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');\n    this.spec.fail({\n      name: 'timeout',\n      message: message\n    });\n\n    this.abort = true;\n    onComplete();\n  } else {\n    this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;\n    var self = this;\n    this.env.setTimeout(function() {\n      self.execute(onComplete);\n    }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);\n  }\n};\n// Mock setTimeout, clearTimeout\n// Contributed by Pivotal Computer Systems, www.pivotalsf.com\n\njasmine.FakeTimer = function() {\n  this.reset();\n\n  var self = this;\n  self.setTimeout = function(funcToCall, millis) {\n    self.timeoutsMade++;\n    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);\n    return self.timeoutsMade;\n  };\n\n  self.setInterval = function(funcToCall, millis) {\n    self.timeoutsMade++;\n    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);\n    return self.timeoutsMade;\n  };\n\n  self.clearTimeout = function(timeoutKey) {\n    self.scheduledFunctions[timeoutKey] = jasmine.undefined;\n  };\n\n  self.clearInterval = function(timeoutKey) {\n    self.scheduledFunctions[timeoutKey] = jasmine.undefined;\n  };\n\n};\n\njasmine.FakeTimer.prototype.reset = function() {\n  this.timeoutsMade = 0;\n  this.scheduledFunctions = {};\n  this.nowMillis = 0;\n};\n\njasmine.FakeTimer.prototype.tick = function(millis) {\n  var oldMillis = this.nowMillis;\n  var newMillis = oldMillis + millis;\n  this.runFunctionsWithinRange(oldMillis, newMillis);\n  this.nowMillis = newMillis;\n};\n\njasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {\n  var scheduledFunc;\n  var funcsToRun = [];\n  for (var timeoutKey in this.scheduledFunctions) {\n    scheduledFunc = this.scheduledFunctions[timeoutKey];\n    if (scheduledFunc != jasmine.undefined &&\n        scheduledFunc.runAtMillis >= oldMillis &&\n        scheduledFunc.runAtMillis <= nowMillis) {\n      funcsToRun.push(scheduledFunc);\n      this.scheduledFunctions[timeoutKey] = jasmine.undefined;\n    }\n  }\n\n  if (funcsToRun.length > 0) {\n    funcsToRun.sort(function(a, b) {\n      return a.runAtMillis - b.runAtMillis;\n    });\n    for (var i = 0; i < funcsToRun.length; ++i) {\n      try {\n        var funcToRun = funcsToRun[i];\n        this.nowMillis = funcToRun.runAtMillis;\n        funcToRun.funcToCall();\n        if (funcToRun.recurring) {\n          this.scheduleFunction(funcToRun.timeoutKey,\n              funcToRun.funcToCall,\n              funcToRun.millis,\n              true);\n        }\n      } catch(e) {\n      }\n    }\n    this.runFunctionsWithinRange(oldMillis, nowMillis);\n  }\n};\n\njasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {\n  this.scheduledFunctions[timeoutKey] = {\n    runAtMillis: this.nowMillis + millis,\n    funcToCall: funcToCall,\n    recurring: recurring,\n    timeoutKey: timeoutKey,\n    millis: millis\n  };\n};\n\n/**\n * @namespace\n */\njasmine.Clock = {\n  defaultFakeTimer: new jasmine.FakeTimer(),\n\n  reset: function() {\n    jasmine.Clock.assertInstalled();\n    jasmine.Clock.defaultFakeTimer.reset();\n  },\n\n  tick: function(millis) {\n    jasmine.Clock.assertInstalled();\n    jasmine.Clock.defaultFakeTimer.tick(millis);\n  },\n\n  runFunctionsWithinRange: function(oldMillis, nowMillis) {\n    jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);\n  },\n\n  scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {\n    jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);\n  },\n\n  useMock: function() {\n    if (!jasmine.Clock.isInstalled()) {\n      var spec = jasmine.getEnv().currentSpec;\n      spec.after(jasmine.Clock.uninstallMock);\n\n      jasmine.Clock.installMock();\n    }\n  },\n\n  installMock: function() {\n    jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;\n  },\n\n  uninstallMock: function() {\n    jasmine.Clock.assertInstalled();\n    jasmine.Clock.installed = jasmine.Clock.real;\n  },\n\n  real: {\n    setTimeout: jasmine.getGlobal().setTimeout,\n    clearTimeout: jasmine.getGlobal().clearTimeout,\n    setInterval: jasmine.getGlobal().setInterval,\n    clearInterval: jasmine.getGlobal().clearInterval\n  },\n\n  assertInstalled: function() {\n    if (!jasmine.Clock.isInstalled()) {\n      throw new Error(\"Mock clock is not installed, use jasmine.Clock.useMock()\");\n    }\n  },\n\n  isInstalled: function() {\n    return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;\n  },\n\n  installed: null\n};\njasmine.Clock.installed = jasmine.Clock.real;\n\n//else for IE support\njasmine.getGlobal().setTimeout = function(funcToCall, millis) {\n  if (jasmine.Clock.installed.setTimeout.apply) {\n    return jasmine.Clock.installed.setTimeout.apply(this, arguments);\n  } else {\n    return jasmine.Clock.installed.setTimeout(funcToCall, millis);\n  }\n};\n\njasmine.getGlobal().setInterval = function(funcToCall, millis) {\n  if (jasmine.Clock.installed.setInterval.apply) {\n    return jasmine.Clock.installed.setInterval.apply(this, arguments);\n  } else {\n    return jasmine.Clock.installed.setInterval(funcToCall, millis);\n  }\n};\n\njasmine.getGlobal().clearTimeout = function(timeoutKey) {\n  if (jasmine.Clock.installed.clearTimeout.apply) {\n    return jasmine.Clock.installed.clearTimeout.apply(this, arguments);\n  } else {\n    return jasmine.Clock.installed.clearTimeout(timeoutKey);\n  }\n};\n\njasmine.getGlobal().clearInterval = function(timeoutKey) {\n  if (jasmine.Clock.installed.clearTimeout.apply) {\n    return jasmine.Clock.installed.clearInterval.apply(this, arguments);\n  } else {\n    return jasmine.Clock.installed.clearInterval(timeoutKey);\n  }\n};\n\n\njasmine.version_= {\n  \"major\": 1,\n  \"minor\": 0,\n  \"build\": 1,\n  \"revision\": 1286311016\n};\n"
  },
  {
    "path": "src/test/spec/bit155/attr.spec.js",
    "content": "/*\n * attr.spec.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// attr\ndescribe('attr', function() {\n  it('should copy arrays', function() {\n    var MyClass = function() {\n      this.data = bit155.attr();\n    };\n    \n    var my = new MyClass();\n    var data = ['hello', 'jello'];\n    my.data(data);\n    \n    expect(my.data()).toEqual(['hello', 'jello']);\n    data.push('bellow');\n    \n    expect(my.data()).toEqual(['hello', 'jello']);\n  });\n  \n  it('should set simple value', function() {\n    var MyClass = function() {\n      this.name = bit155.attr();\n    };\n    var my = new MyClass();\n    \n    expect(my.name('dave')).toEqual(my);\n    expect(my.name()).toEqual('dave');\n  });\n\n  it('should set array value', function() {\n    var MyClass = function() {\n      this.name = bit155.attr();\n    };\n    var my = new MyClass();\n    \n    expect(my.name('dave', 'heaton')).toEqual(my);\n    expect(my.name()).toEqual(['dave', 'heaton']);\n  });\n  \n  it('should use initial value', function() {\n    var MyClass = function() {\n      this.name = bit155.attr({\n        initial: 'anne'\n      });\n    };\n    var my = new MyClass();\n    \n    expect(my.name()).toEqual('anne');\n  });\n\n  it('should not filter initial value', function() {\n    var MyClass = function() {\n      this.name = bit155.attr({\n        initial: 'anne',\n        filter: function(v) { return v.toUpperCase(); }\n      });\n    };\n    var my = new MyClass();\n    \n    expect(my.name()).toEqual('anne');\n  });\n\n  it('filter should assign different value', function() {\n    var MyClass = function() {\n      this.name = bit155.attr({\n        filter: function(v) { return v.toUpperCase(); }\n      });\n    };\n    var my = new MyClass();\n    \n    expect(my.name('dave')).toEqual(my);\n    expect(my.name()).toEqual('DAVE');\n  });\n\n  it('filter validator should throw error', function() {\n    var MyClass = function() {\n      this.name = bit155.attr({\n        filter: function(v) { if (typeof v !== 'string') throw 'Bad value'; }\n      });\n    };\n    var my = new MyClass();\n    \n    expect(my.name('dave')).toEqual(my);\n    expect(my.name()).toEqual('dave');\n    expect(function(){ my.name(42); }).toThrow('Bad value');\n    expect(my.name()).toEqual('dave');\n  });\n  \n  it('should invoke after callback', function() {\n    var callbackValue;\n    var MyClass = function() {\n      this.name = bit155.attr({\n        callback: function(v) { callbackValue = true; }\n      });\n    };\n    var my = new MyClass();\n    \n    expect(my.name('dave')).toEqual(my);\n    expect(callbackValue).toEqual(true);\n    expect(my.name()).toEqual('dave');\n  });\n  \n  it('filter and callback should have access to object', function() {\n    var beforeThis, afterThis;\n    var MyClass = function() {\n      this.name = bit155.attr({\n        filter: function(v) { beforeThis = this; }, \n        callback: function(v) { afterThis = this; }\n      });\n    };\n    var my = new MyClass();\n    \n    expect(my.name('dave')).toEqual(my);\n    expect(beforeThis).toEqual(my);\n    expect(afterThis).toEqual(my);\n    expect(my.name()).toEqual('dave');\n  });\n});\n"
  },
  {
    "path": "src/test/spec/bit155/csv.spec.js",
    "content": "/*\n * csv.spec.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// csv\ndescribe('csv', function() {\n  // cell\n  describe('cell', function() {\n    it('should encode undefined', function() {\n      expect(bit155.csv.cell()).toEqual('');\n    });\n    it('should encode null', function() {\n      expect(bit155.csv.cell(null)).toEqual('');\n    });\n    it('should encode number', function() {\n      expect(bit155.csv.cell(1)).toEqual('1');\n    });\n    it('should encode string', function() {\n      expect(bit155.csv.cell('my string')).toEqual('my string');\n    });\n    it('should keep newlines', function() {\n      expect(bit155.csv.cell('my\\nstring')).toEqual('\"my\\nstring\"');\n    });\n    it('should not escape commas, only quote', function() {\n      expect(bit155.csv.cell('my, string')).toEqual('\"my, string\"');\n    });\n    it('should escape quotes', function() {\n      expect(bit155.csv.cell('my \"string\"')).toEqual('\"my \"\"string\"\"\"');\n    });\n    it('should not escape backspace', function() {\n      expect(bit155.csv.cell('my\\\\string')).toEqual('my\\\\string');\n    });\n    it('should escape lots', function() {\n      expect(bit155.csv.cell('my\\n\"string\" is, awesome\\\\wicked')).toEqual('\"my\\n\"\"string\"\" is, awesome\\\\wicked\"');\n    });\n    it('should not trim', function() {\n      expect(bit155.csv.cell('  boo,  ')).toEqual('\"  boo,  \"');\n    });\n    it('should escape multiple quotes', function() {\n      expect(bit155.csv.cell('2.5\" / 230,000 px')).toEqual('\"2.5\"\" / 230,000 px\"');\n    });\n    \n  });\n  \n  // row\n  describe('row', function() {\n    it('should encode empty row', function() {\n      expect(bit155.csv.row()).toEqual('');\n    });\n    it('should encode empty row array', function() {\n      expect(bit155.csv.row([])).toEqual('');\n    });\n    it('should encode null values varargs', function() {\n      expect(bit155.csv.row(null, null)).toEqual(',');\n    });\n    it('should encode null values array', function() {\n      expect(bit155.csv.row([null, null])).toEqual(',');\n    });\n    it('should not encode object values', function() {\n      expect(bit155.csv.row({name: 'hello'})).toEqual('[object Object]');\n    });\n  });\n  \n  // csv\n  describe('csv', function() {\n    it('should encode nothing', function() {\n      expect(bit155.csv.csv()).toEqual('');\n    });\n    it('should encode an empty array', function() {\n      expect(bit155.csv.csv([])).toEqual('');\n    });\n    it('should encode a 2d array single row', function() {\n      expect(bit155.csv.csv([ ['one','two,too,to'] ])).toEqual('one,\"two,too,to\"\\n');\n    });\n    it('should encode a 2d array two rows', function() {\n      expect(bit155.csv.csv([ ['one','two'], [3, 'four or \"for\"'] ])).toEqual('one,two\\n3,\"four or \"\"for\"\"\"\\n');\n    });\n  });\n});\n"
  },
  {
    "path": "src/test/spec/bit155/scraper.spec.js",
    "content": "/*\n * scraper.spec.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\ndescribe('scraper', function() {\n  describe('xpathForSelection', function() {\n  });\n});"
  },
  {
    "path": "src/test/spec/jquery-commonAncestor.spec.js",
    "content": "/*\n * jquery-commonAncestor.spec.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\ndescribe('commonAncestor', function() {\n  it('should select common ancestor of two siblings', function() {\n    var table1 = $('<table>');\n    var table1_tr1 = $('<tr>').appendTo(table1);\n    var table1_tr1_td1 = $('<td>').appendTo(table1_tr1);\n    var table1_tr1_td2 = $('<td>').appendTo(table1_tr1);\n    var table1_tr1_td2_p = $('<p>').appendTo(table1_tr1_td2);\n    \n    expect($(table1_tr1_td1, table1_tr1_td1).commonAncestor().get(0)).toEqual(table1_tr1.get(0));\n  });\n\n  it('should select common ancestor of element and its aunt', function() {\n    var table1 = $('<table>');\n    var table1_tr1 = $('<tr>').appendTo(table1);\n    var table1_tr1_td1 = $('<td>').appendTo(table1_tr1);\n    var table1_tr1_td2 = $('<td>').appendTo(table1_tr1);\n    var table1_tr1_td2_p = $('<p>').appendTo(table1_tr1_td2);\n    \n    expect($(table1_tr1_td1, table1_tr1_td2_p).commonAncestor().get(0)).toEqual(table1_tr1.get(0));\n  });\n  \n  it('should select parent as common ancestor of element and its parent', function() {\n    var table1 = $('<table>');\n    var table1_tr1 = $('<tr>').appendTo(table1);\n    var table1_tr1_td1 = $('<td>').appendTo(table1_tr1);\n    var table1_tr1_td2 = $('<td>').appendTo(table1_tr1);\n    var table1_tr1_td2_p = $('<p>').appendTo(table1_tr1_td2);\n    \n    expect($(table1_tr1_td1, table1_tr1).commonAncestor().get(0)).toEqual(table1_tr1.get(0));\n  });\n\n  it('should select no common ancestor of unrelated elements', function() {\n    var table1_tr1_td1 = $('<td>');\n    var table1_tr1_td2 = $('<td>');\n    \n    expect($(table1_tr1_td1, table1_tr1_td1).commonAncestor().get(0)).toBeUndefined();\n  });\n  \n});"
  },
  {
    "path": "src/test/spec/jquery-serializeParams.spec.js",
    "content": "/*\n * jquery-serializeParams.spec.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// serializeParams\ndescribe(\"serializeParams\", function() {\n  it('should ignore malformed names', function() {\n    var form = $('<form><input name=\"foo[\" value=\"bar\"></form>');\n    var params = form.serializeParams();\n    \n    expect(params).toEqual({\n      'foo[': 'bar'\n    });\n  });\n  \n  it('should deal with typical names', function() {\n    var form = $('<form>')\n      .append($('<input name=\"foo\" value=\"bar\">'))\n      .append($('<input name=\"jabber\" value=\"wocky\">'));\n    var params = form.serializeParams();\n    \n    expect(params).toEqual({\n      foo: 'bar',\n      jabber: 'wocky'\n    });\n  });\n  \n  it('should create array for multiple values', function() {\n    var form = $('<form>')\n      .append($('<input name=\"foo\" value=\"bar\">'))\n      .append($('<input name=\"foo\" value=\"wocky\">'));\n    var params = form.serializeParams();\n    \n    expect(params).toEqual({\n      foo: ['bar', 'wocky']\n    });\n  });\n\n  it('should collect collisions in a different place if there are empty brackets', function() {\n    var form = $('<form>')\n      .append($('<input name=\"attributes[][name]\" value=\"name1\">'))\n      .append($('<input name=\"attributes[][type]\" value=\"type1\">'))\n      .append($('<input name=\"attributes[][name]\" value=\"name2\">'))\n      .append($('<input name=\"attributes[][type]\" value=\"type2\">'));\n    var params = form.serializeParams();\n    \n    expect(params).toEqual({\n      'attributes': [\n        { name: 'name1', type: 'type1' },\n        { name: 'name2', type: 'type2' }\n      ]\n    });\n  });\n});"
  },
  {
    "path": "src/test/spec/jquery-xpath.spec.js",
    "content": "/*\n * jquery-serializeParams.spec.js\n *\n * Author: dave@bit155.com\n *\n * ---------------------------------------------------------------------------\n * \n * Copyright (c) 2010, David Heaton\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *  \n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *  \n *      * Neither the name of bit155 nor the names of its contributors\n *        may be used to endorse or promote products derived from this software\n *        without specific prior written permission.\n *  \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// serializeParams\ndescribe(\"xpath\", function() {\n  it('should generate indices for all elements with siblings', function() {\n    var struct = $('<div>')\n      .append($('<ul>')\n        .append($('<li>'))\n        .append($('<li>')\n          .append($('<a>')\n            .append($('<span>'))\n            .append($('<span>'))\n          )\n          .append($('<a>'))\n        )\n        .append($('<li>'))\n      );\n      \n    expect(struct.find('span').xpath()).toEqual('/div/ul/li[2]/a[1]/span[1]');\n  });\n\n});"
  },
  {
    "path": "src/viewer.html",
    "content": "<!DOCTYPE html>\n<!-- Copyright (c) 2010, David Heaton\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n \n     * Neither the name of bit155 nor the names of its contributors\n       may be used to endorse or promote products derived from this software\n       without specific prior written permission.\n \nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -->\n<html>\n<head>\n  <title>Scraper</title>\n  \n  <link rel=\"stylesheet\" href=\"lib/jquery-ui-1.8.6/css/custom-theme/jquery-ui-1.8.6.custom.css\" type=\"text/css\">\n  <link rel=\"stylesheet\" href=\"css/viewer.css\" type=\"text/css\">\n\n  <script type=\"text/javascript\" src=\"lib/jquery-ui-1.8.6/js/jquery-1.4.2.js\"></script>\n  <script type=\"text/javascript\" src=\"lib/jquery-ui-1.8.6/js/jquery-ui-1.8.6.js\"></script>\n  <script type=\"text/javascript\" src=\"lib/datatables-1.7.4/js/jquery.dataTables.js\"></script>\n  <script type=\"text/javascript\" src=\"lib/jquery.tablednd_0_5.js\"></script>\n  <script type=\"text/javascript\" src=\"lib/jquery.layout-1.2.0.js\"></script>\n  <script type=\"text/javascript\" src=\"js/shared.js\"></script>\n  <script type=\"text/javascript\" src=\"js/bit155/csv.js\"></script>\n  <script type=\"text/javascript\" src=\"js/bit155/attr.js\"></script>\n  <script type=\"text/javascript\" src=\"js/bit155/scraper.js\"></script>\n  <script type=\"text/javascript\" src=\"js/viewer.js\"></script>\n\n</head>\n<body>\n  <div id=\"about\">\n    <h1>Scraper</h1>\n    <h2>By <a href=\"http://bit155.com\" target=\"_blank\">Dave Heaton</a></h2>\n    <p>\n      Built on the shoulders of\n      <a href=\"http://jquery.com\" target=\"_blank\">jQuery</a> and \n      <a href=\"http://jqueryui.com\" target=\"_blank\">jQuery UI</a>, as well as \n      <a href=\"http://layout.jquery-dev.net/\" title=\"UI.Layout Plug-in - Home 2\" target=\"_blank\">jQuery Layout</a>,\n      <a href=\"http://www.datatables.net/\" title=\"DataTables (table plug-in for jQuery)\" target=\"_blank\">DataTables</a> and\n      <a href=\"http://www.isocra.com/2008/02/table-drag-and-drop-jquery-plugin/\" title=\"Table Drag and Drop JQuery plugin | Isocra\" target=\"_blank\">TableDnD</a>\n      plugins.\n    </p>\n    <p>\n      Some of the icons used in this extension are from the generous\n      <a href=\"http://p.yusukekamiyamane.com/\" target=\"_blank\">Yusuke Kamiyamane</a>.\n    </p>\n    <dl>\n      <dt>Project Page</dt>\n      <dd><a href=\"http://mnmldave.github.com/scraper/\" target=\"_blank\">http://mnmldave.github.com/scraper/</a></dd>\n      <dt>License</dt>\n      <dd><a href=\"license.html\" target=\"_blank\">BSD License</a></dd>\n    </dl>\n  </div>\n  \n  <div id=\"presets\">\n    <p>\n      Save your current settings as a preset to quickly restore them in the \n      future.\n    </p>\n    <form id=\"presets-form\">\n      <input id=\"presets-form-name\" name=\"name\" type=\"text\" value=\"\">\n      <input type=\"submit\" value=\"Save\">\n    </form>\n    <ul id=\"presets-list\">\n    </ul>\n  </div>\n  \n  <form id=\"options\" class=\"ui-layout-west\">\n    <div id=\"options-header\">\n      <div id=\"options-meta-page\"></div>\n    </div>\n    \n    <div id=\"options-center\" class=\"ui-layout-content\">\n      <fieldset>\n        <legend>Selector</legend>\n        <table id=\"options-selector-table\">\n          <tr>\n            <td nowrap width=\"0%\">\n              <select id=\"options-language\" name=\"language\">\n                <optgroup label=\"Language\">\n                  <option value=\"jquery\">jQuery</option>\n                  <option value=\"xpath\">XPath</option>\n                </optgroup>\n              </select>\n            </td>\n            <td nowrap width=\"100%\">\n              <input id=\"options-selector\" name=\"selector\" type=\"text\" placeholder=\"Selector\" />\n            </td>\n          </tr>\n          <tr>\n            <td>\n            </td>\n            <td>\n              <div id=\"options-language-help\"></div>\n            </td>\n          </tr>\n        </table>\n      </fieldset>\n      \n      <fieldset>\n        <legend>Columns</legend>\n        <p></p>\n        <table id=\"options-attributes\">\n          <thead>\n            <tr>\n              <th>&nbsp;</th>\n              <th>XPath</th>\n              <th>Name</th>\n              <th>&nbsp;</th>\n            </tr>\n          </thead>\n          <tbody></tbody>\n        </table>\n      </fieldset>\n      \n      <fieldset id=\"options-filters\">\n        <legend>Filters</legend>\n        <input id=\"options-filters-empty\" type=\"checkbox\" name=\"filters[]\" value=\"empty\">\n        <label for=\"options-filters-empty\" title=\"Results containing empty values for all attributes will not be returned.\">Exclude empty results</label>\n        <br/>\n      </fieldset>\n    </div>\n    \n    <div id=\"options-footer\" class=\"pane-footer\">\n      <table>\n        <tr>\n          <td>\n            <a id=\"options-presets-button\" class=\"button\" href=\"javascript:;\">Presets...</a>\n            <a id=\"options-reset-button\" class=\"button\" href=\"javascript:;\">Reset</a>\n          </td>\n          <td><input id=\"options-submit\" type=\"submit\" value=\"Scrape\"></td>\n        </tr>\n      </table>\n    </div>\n  </form>\n\n  <div id=\"center\" class=\"ui-layout-center\">\n    <div id=\"results-table\" class=\"ui-layout-content\">\n    </div>\n\n    <div id=\"export\" class=\"pane-footer\">\n      <table>\n        <tr>\n          <td><a id=\"about-link\" href=\"http://mnmldave.github.com/scraper/\" target=\"_blank\"><img src=\"img/question.png\"></a></td>\n          <td>\n            <form action=\"\">\n              <input id=\"export-google\" type=\"submit\" value=\"Export to Google Docs...\">\n            </form>\n          </td>\n        </tr>\n    </div>\n  </div>\n</body>\n</html>"
  }
]